question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Python idioms in the API

See original GitHub issue

The README mentions that:

So far this extension has been written by folks who are primarily Rust programmers, so it’s highly likely that there’s some faux pas in terms of Python idioms. Feel free to send a PR to help make things more idiomatic if you see something!

Indeed, after using the API for a while I noticed a few aspects that aren’t quite in line with Python conventions, though some of them are harder to ignore than others.

  1. Nullary getter methods like ExportType.name that always succeed and always return the same value are a pretty clear-cut case for using Python properties instead. This is, by far, the least idiomatic aspect of the library, and it’s very easy to miss a () that feels like it shouldn’t be there.
  2. There are lots of unary setter methods like Config.debug_info named after the property they’re changing, and there is a good case for using Python setter-only properties instead. (As a bonus, if wasi-c-api ever adds getters for them, they could be made readable in a backwards compatible way.) This doesn’t change much for e.g. Config, but for Linker for example allow_shadowing works like a simple setter with no side effects, but define_wasi, while similarly imperatively named and used, irreversibly changes its state.
  3. Nullary casting methods like ExternType.func_type feel very odd overall. 1. They’re named like accessors, but they work like dynamic_cast. 2. The naming is inconsistent for conversion in different directions—FuncTypeExternType conversion is done by as_extern, but ExternTypeFuncType conversion is performed by func_type. 3. My impression so far is that most uses of these casting methods are in contexts where a specific type is expected, in which case it would be more convenient if they raised TypeError instead of returning None. (If they did, another method would be necessary to dispatch on an unknown type.)
  4. Val.get_* introduces a third naming scheme for type conversion functions, one that clashes in meaning with e.g. Instance.get_export.
  5. *.get_export() methods seem like they would only fail in truly exceptional conditions and so also appear good candidates for raising an exception instead of returning None.

To summarize:

  1. I would change simple getters and setters to be properties.
  2. I would rename all casting methods to as_*().
  3. I would change *.get_export() to raise if the export is not found (this is particularly important for Caller.get_export(), since currently it looks like there is no way to distinguish the cases of “export does not exist” and “the caller is gone” at all, even for debugging, and the exception message would allow that).
  4. I would probably change the dynamic casting methods to raise if the type is wrong, and add a matching is_* method for the cases where dynamic dispatch is indeed necessary. I’m not completely certain about this one, but it seems that currently, dynamic dispatch would look something like:
if extern.memory():
    do_something_with_memory(extern.memory())
elif extern.table():
    do_something_with_table(extern.table())

so changing it to:

if extern.is_memory():
    do_something_with_memory(extern.as_memory())
elif extern.is_table():
    do_something_with_table(extern.as_table())

doesn’t really make it any worse.

What do you think? All of these changes are likely to break most existing code, so I’d rather discuss them before working on a PR.

Also, I should mention that “do nothing” is an option. In general Python libraries are a lot looser with conventions than libraries in many other languages; I’d rather see the API improved, personally, but the current one isn’t drastically more inconsistent than what one would expect in general.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
whitequarkcommented, Apr 27, 2020

3. I’m not as sure about get_export raising an exception, to me it makes sense for None (or undef in my case) to be returned when you ask for something that doesn’t exist.

This is actually an established and widespread Python idiom called EAFP. Personally, I follow it very cautiously; for example, dictionary indexing raising KeyError that you are supposed to catch is a source of subtle bugs because the try: except: construct is unwieldy and it is tempting to put something besides the index operation itself in the try: expression, but of course now you may have caught an exception raised by third party code that should have bubbled up.

In this case however, assuming my intuition about the use of .get_export() is correct–that the vast majority of invocations are likely to succeed, and failures indicate logic errors–it seems like a solid case for that idiom. Consider that it would work much like the built-in dictionaries.

0reactions
whitequarkcommented, Apr 29, 2020

Thanks for the fix!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Idiomatic Python. Coding the smart way. - Medium
Python has code style guidelines and idioms. Idioms in a programming language let future readers know exactly what we're trying to do.
Read more >
Automatic Recommendation of Pythonic Idiom Usage For Pull ...
Abstract—Pythonic code is idiomatic code that follows guiding principles and practices within the Python community. Offering performance and ...
Read more >
A collection of design patterns/idioms in Python - GitHub
A collection of design patterns/idioms in Python. Contribute to faif/python-patterns development ... facade, use one class as an API to a number of...
Read more >
Transforming Code into Beautiful, Idiomatic Python - YouTube
Raymond HettingerLearn to take better advantage of Python's best features and improve existing code through a series of code transformations ...
Read more >
Idiomatic Python - Adapter Pattern - hectormartinez.dev
For Python, we would like to have a more Pythonic API, with Python idioms and syntactic conventions into the RDKit API. To do...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found