Hacker News new | ask | show | jobs
by jnhnum1 4791 days ago
Other author here: Like lihaoyi said, it's true that the way we defined things doesn't match standard Python namespacing, but it saves some typing and I think it's easy to get used to the semantics of our case classes. Our macro just transforms the "namespace tree" that you would normally get from writing code like that into an "inheritance tree", where all the subclasses' names are at the level of the top class. If you wanted to do something like this with proper namespaces, you can probably do something similar without macros using metaclasses.
2 comments

> it saves some typing

Your macropy is very interesting, but please do not use this argument. "Saving some typing" is the least interesting side-effect of some macros.

To clarify my point: in most of the industry, we all fight hard to garden big codebases with intricate dependency problems. I am convinced that code complexity management is very far from a solved problem, and I hope advanced tools like macros can help there.

But "saving a few keystrokes" is very often at the heart of the stupides issues we have with code complexity.

Two examples:

+ "from x import " <-- this saves a few typing, but it become extremely annoying as soon as your code get more than 10 modules.

+ template.render(tpl_file, locals()) <-- this feeds the template space with shit and makes it much harder to trace data between templates and models. I daily revile the guy who typed the "*locals()" in the Mako doc.

I urge you to take this criticism more seriously. With your library a programmer is changing the semantics of class nesting in the language, all by pre-pending a very missable and ambiguous @case to the class. I'm no expert but I think this is pretty bad in any language, and especially one that says "explicit is better than implicit"
We do take it seriously; it's a hard tradeoff between Novelty and Utility. Given that the whole point of macros is to change the semantics of the Python language, this (valid) criticism applies not just to case classes but macros in general. If you go haywire with macros, all hell breaks loose.

We think that with some discipline, it is possible to come up with macro transformations which are both useful and understandable by a programmer. This means setting clearly defined semantics for the transformations, which is difficult but doable.

If you think macros are kinda crazy (well, they are!) you should look at the implementation of such pythonic constructs like `namedtuple`, the `ast` module and the new Enum library coming out!

The implementation of namedtuple is pretty crazy, but the interface is simple and doesn't change the language semantics.
I'd argue that "fields as a string with spaces inside, or maybe a list of strings" is changing language semantics quite a bit.

We're used to namedtuples doing it like this now, but if namedtuples didn't exist, "fields as a list of strings with spaces inside, or maybe a list of strings" would definitely not make it past code review and probably get me yelled at by my future colleagues.

Yes, it could be bad, but at the same time the "@case" isn't the only indicator that this class is special. A case class definition can be very visually distinct compared to a normal class.

One thing case classes let you do is implement functionality externally to a class using pattern-matching functions. When you do this, your case class definition will consist of nothing but empty class definitions:

  @case
  class List:
    class Nil():  pass
    class Cons(x, xs): pass
In any case, Python's enums will use fully qualified names, so we may change our current system for compatibility and consistency.