templating opEquals/opCmp (e.g. for DSL/expression templates)

Nicholas Wilson iamthewilsonator at hotmail.com
Thu Feb 14 01:39:12 UTC 2019


On Wednesday, 13 February 2019 at 18:42:43 UTC, H. S. Teoh wrote:
> On Wed, Feb 13, 2019 at 01:50:21AM +0000, Nicholas Wilson via 
> Digitalmars-d wrote:
>> On Wednesday, 13 February 2019 at 00:56:48 UTC, H. S. Teoh 
>> wrote:
>> > The usual invocation of such a DSL as a compile-time 
>> > argument, say something like this:
>> > 
>> > 	myDsl!'a <= b'
>> > 
>> > contains one often overlooked, but very important element: 
>> > the identifier `myDsl`, that sets it apart from other uses 
>> > of `<=`, and clearly identifies which interpretation should 
>> > be ascribed to the symbols found in the template argument.
>> 
>> Its also much uglier and does not commute with things that use 
>> <= i.e. generic functions.
>
> Ugliness is debatable; I find that the identifier serves as a 
> good marker to indicate departure from usual semantics.

All of the examples in the thread are context-free. The 
distinction between eval now to a bool vs other uses should be a 
lot more pronounced with the context of the surrounding code. Or 
you simply just don't care.

> As for [myDsl!'<'] not commuting with generic functions, do you 
> have a specific example in mind?  Because all the obvious (to 
> me) examples I can think of are cases where I think would be 
> better off *not* working with generic code, because the generic 
> code expects one set of semantics but overloading 
> opCmp/opEquals to return arbitrary objects produce a different 
> set of semantics.

Math kernels. kern!float would be a scalar form, kern!float4 
would be vectorised, kern!Expression would be something you could 
pass to e.g. TensorFlow.

>> No. auto y = p <= q; should not e.g. open a socket (you could 
>> probably do that already with an impure opCmp). Being able to 
>> capture the expression `p <= q` is the _entire point_ of the 
>> proposal.
>
> And that's the point I disagree on.  The current expectation of 
> a line of code like `auto y = p <= q;` is that typeof(y) == 
> bool.  For it to return a type other than bool is unexpected 
> behaviour,

Such is the nature of change.

> and leads to subtle differences in semantics

Which should be obvious from the context of the code, or you 
simply don't care about the distinction.

> that will likely result in bugs.

I don't think so. Compile errors yes, because types won't match. 
But bugs?

> Explicitly marking it, e.g., as `auto y = symbolic!"p <= q";` 
> makes it much more obvious what's really going on with the code.

Again these examples are context free: You know the types of p 
and q.
and if you don't (generic code) then you simply don't care. Also 
if you have a page full of `symbolic!"blah"` you're pretty 
quickly going to lose the forest for the trees, especially when 
you have opBinary overloaded to symbolics without 
`symbolic!"blah"`.

> Yes it's ugly, but at the same time this ugliness is IMO 
> necessary warning for the would-be code maintainer to 
> understand that the semantics depart from the usual 
> expectations.

You have comments for that.

> My point was that there are no such operators as ∘ or ± in D, 
> so even if you had free-for-all operator overloading you 
> couldn't implement such an expression.  Using a DSL frees you 
> from that constraint.
>
> And because there are no such operators in D, they have no 
> standard meaning defined by the language, so different authors 
> likely have different definitions for them.

Most of those operators have standard definitions in math which 
makes that point moot. And if you're making up operators 
willy-nilly then you should expect to end up with an 
unmaintainable mess. I'm not catering for those kind of people.

> So even in the case where you *could* add arbitrary operators 
> to the language, you'll end up with a mess as soon as your code 
> imports two libraries that happen to overload some of the same 
> custom operators -- it would be hard to tell which set of 
> semantics apply to the operators in any given piece of code; 
> you'd have to study the context to be sure.

All you need to know are the types involved and more usefully 
what module they come from, which any decent editor with plugin 
should be able to tell you.

> Having the `eval` or whatever else prefixed identifier in front 
> of the DSL resolves that question instantly.

Yes but does it need to be there? (aside the missing bounds and 
ambiguity of the integral) I'd be surprised if that wasn't valid 
Julia code. Now I'm not suggesting we go that far, having 
arbitrary unicode operators would be a nightmare, what with 
normalisation and all (not to mention trying to ender the damn 
things on a keyboard).



More information about the Digitalmars-d mailing list