So I am quite on board with:
Well, not necessarily that, but that I think some customised DSL environment could be helpful for various applications.
Of course it is always possible to just implement custom DSL via string-parsing, but the issue with it is that inevitably is going to be very slow and would not be attractive for ad-hoc applications, such as "None-aware operators:
%timeit 1 if a is None else 2 # 15 ns
well, ok, this is a bit wishful thinking, but let’s say maybe
class that I have been playing with
d = {'a': [1]}
%timeit maybe(d)['a'][0] | 2 # 1.3 µs
In comparison to something that parses string:
import string
FMTR = string.Formatter()
%timeit FMTR.format('{} {} {}', 1, 2, 3) # 4 µs
And this is lower bound. To make it do what maybe
does above it would easily go to 10µs, maybe even 20µs.
E.g. Symbolic expression parsing:
s = '(-1 * -2) + (-3 * 2) + (-4 * -1 * -3)'
parser.parse(s) # 50 µs
And this is a reasonable performance as this is very minimal optimised implementation. E.g. performance of lark
doing the same thing:
parser.parse(s) # 160 µs
cython_parser.parse(s) # 120 µs
So I think all I am trying to say is that implementing string DSL can definitely be easily done. e.g.:
a = maybe('a | b & c[d].e', a=1, b=2, c=3, d=4)
But it would be both:
a) very slow (in comparison to something done in Python)
b) inconvenient as parameters would inevitably have to be provided manually (not simply looked up)
However the issue with something like:
WithDeferredContext{ a | b & c[d].e } # pseudo-code
is that for this to be justified it needs to be a proper multi-purpose tool (such as re
for string parsing) as opposed to just be able to fit one problem.