Andrei Alexandrescu wrote:
Ary Borenszweig wrote:
Andrei Alexandrescu escribió:
Nice! :-)

I showed the Fibonacci example to a friend of mine and he said "that string stuff scares me a little". The same happens to me.

What kind of error do you get if you mistype something in that string expression?

Let me see. Say I made the mistake of using "b":

auto fib = series!("a[n-1] + b[n]")(1, 1);

std/functional.d(185): static assert "Bad binary function: a[n] + b[n-1] for types Cycle!(int[]) and uint. You need to use an expression using symbols a and n."

Heck, that's even better than compiler's own error messages. Unfortunately, the line where the actual instantiation was invoked is not shown. I think that's entirely doable though.

In BLADE, what I did was provide an error message as an alternate return value from the inner templates. This is then passed down through the higher-level functions. At the user level, instead of mixing in code to invoke the function, it mixes in a static assert(0, errormsg) instead. Then there is an error ONLY on the line of user code. You can only achieve these perfect error messages if you have a mixin statement in the user code, unfortunately.

Of course, using return values to indicate errors is so 1970's. Compile-time assert exception catching would be so much better... But a simple change to the static assert handling would get us most of the way there.


Say I forget to close a bracket:

auto fib = series!("a[n] + a[n-1")(1, 1);

The compiler penalizes that by never finishing compiling. That's a bug.

There's a few cases in bugzilla about mismatched brackets. Some of them cause segfaults.


Can you pass a delegate instead of a string? Something like:

auto fib = series!((Range a, int n) { return a[n-1] + a[n]; })(1, 1);

Not right now because delegate literals can't be templates. But I talked about that with Walter and he'll make it work.

That seems much safe and will probably give a reasonable error if you mistype something. I know, it's longer than the previous one. But it would be nice if D had the following rule (or something similar to it): "if a delegate doesn't return, the last statement is converted to a return" (and you can ommit the semicolon). So now you can write:

auto fib = series!((Range a, int n) { a[n-1] + a[n] })(1, 1);

And if you could just ommit the types in the delegate...

auto fib = series!((a, n) { a[n-1] + a[n] })(1, 1);

Still a little longer than the original, but you get all the benefits of not using a string.

Incidentally, I was talking to Walter about the shorter delegate form and he convinced me that it's too risky to have semantics depend on only one semicolon. But omitting the type names from a literal delegate is something we're mulling over.

The truth is, the reasons against using strings for short functions are shrinking. I mean, you don't want to not use strings just to not use strings, right? I hope I convinced you that strings are unbeatable for short functions that don't need access to local state, their efficiency is exemplary, and their error messages are not half bad.


Andrei

Reply via email to