Hacker News new | past | comments | ask | show | jobs | submit login

What’s with the macros? With Python you can build fully-featured DSLs without needing macros by simply overriding standard operators.



True, you can but it results in a more limited DSL. This is mainly due to variable names needing to exist, be a valid object and chained used method invocations, which results in more awkward expressions (IMHO). Importantly macros enable compile time checking of a DSL rather than only runtime checking. That alone is very powerful.

Take a SQL query in Python's SQLAlchemy:

   s = select([db.func.sum(users.c.id)]).\
       .select_from(
           Users.outerjoin(Posts, Users.id == Posts.user_id))
       where(and_(
           users.c.id == a1.c.user_id,
           users.c.id == a2.c.user_id,
           a1.c.email_address == 'jack@msn.com',
           a2.c.email_address == 'jack@yahoo.com'
       )).\
       group_by(users.c.age)
That's not bad, but compare it to a similar query in Elixir's Ecto:

   from account in App.Account,
       left_join: t0 in App.Transaction,
       on: t0.account_id == account.id
            and t0.user_id == ^current_user.id
            and t0.deleted == false
            and t0.type == "inflow",
       where: account.id == ^id and t1.user_id == t0.user_id,
       group_by: account.id,
       select: {account, {sum(t0.amount), sum(t1.amount)}})
The Elixir DSL allows a bit more flexibility when re-using language built-in's such as `and`/`or`, or undefined ones likes `sum` without needing the hacked names like `and_` or `db.func.sum` as in Python (or Java or others OOs). Generally the formatting is easier with macro based DSL's.

P.S. The examples might not be exactly correct as I cobbled a couple of different ones together.


Very cool, does it compose?

Some statically typed languages allow you to build up composable query snippets along the lines of (from a Scala DSL):

    val accountQ = for {
      (a, t) <- Account leftJoin Transaction (_.id is _.accountId)
      if a.id is ... && t.userId ...
      groupBy a.id
    } yield (a, t.id, t.amount.sum, ...)

    val invoiceQ = for {
      (a, transId, total) <- accountQ
      i <- Invoice join (_.transId is transId) 
    } yield (a, i, total)
Basically you can build up arbitrarily complex queries, all compile time checked -- it's really quite wonderful. Haskell has something similar with Esqueleto and C#/F# has LINQ to SQL.

I love query DSLs, the more we move away from string-y SQL the better :)


Ecto is pretty composeable [1]. Having a compile time checked SQL DSL was always one of the biggest features I wanted back in my Java days.

1: https://elixirschool.com/blog/ecto-query-composition/


I agree - the truth is that in Python it's easy to define DSLs only if they consist of expressions.

It's not that easy to define an arbitrary language that allows you to write code that is close to something else completely (like Ecto vs SQL).


Can you give an example? I've never heard people talk about Python DSLs (just Lisp, Smalltalk, Rebol, and Forth usually).


Theano: http://deeplearning.net/software/theano/library/index.html

Define arbitrary execution graphs that compile to GPU or CPU.


Polymage is a good example: http://mcl.csa.iisc.ac.in/polymage.html#examples

Python embedded DSL for image processing / general matrix munging




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: