Dynamic D

Adam D. Ruppe destructionator at gmail.com
Tue Jan 4 08:03:28 PST 2011


Lutger Blijdestijn wrote:
> The restriction with calling zero-args functions is unfortunate,
> could this be solved by turning it into a class and dynamically
> checking whether the type is a function and then invoke it if it is?

Maybe, but I think it'd still break the property get, which
breaks setting complex types. This, and your other concern about
implicit declarations are actually caused by the same root
problem: the imperfect compiler implementation of properties
combined with variadic opDispatch templates.

(Like I said in that other thread, each of those features works
quite well on its own, but the combination reveals some minor
bugs.)


To set a complex type, you do the:

dyn.property() = some fancy thing;

Which returns a property by reference, then does its opAssign
template, which is much more capable of fanciness than the
runtime variadic function you get without the parenthesis.

Why do that? Because overloading on property and non-property
doesn't work right now. Through trial and error, I found
the compiler doesn't add a property assignment's type to the
template argument list, but does pass it as a func argument.
(Quite possibly a (minor) compiler bug itself - I may be
depending on one bug to work around another!)

So, if you try to do a template, it will complain about wrong
number of arguments to the function. A variadic function gets
that error to go away and I can handle it at runtime. This comes
with trade-offs though: the big one being that it doesn't work
with complex types. Like the code's comment says, I really need
the compiler's help to make them work, and it isn't around by
the time any of that code is actually run.


The best situation would be:

@property Dynamic opDispatch(string fieldName)() // getter
Dynamic opDispatch(string fieldName, T...)(T t) // function call,
                                              // any num of args
@property Dynamic opDispatch(string fieldName, T)(T t) // setter

Then everything would Just Work, without the limitations of
the runtime variadic and associated workarounds. But the first
two are broken by @property not being recognized in overloads
currently*, and the last is broke by the right-hand side of the
property assignment not being passed as a template argument.


* My preferred fix here would be to give @property one more point
in overload resolution so it is slightly preferred over non-property
in these situations, but otherwise do nothing. It's the most
conservative solution here. I looked at dmd's code, but I don't
know the compiler well enough to make it happen.

I guess if @property was strengthened, I could work with that too,
just by adding an opCall and leaving opDispatch to do nothing but
get and set. The property assign not being passed to the template
would have to be solved somehow there too though.



Anyway, none of the fixes are in place today, so I had to make
a choice - either setting requires a named function call or
zero arg calling requires a named function. I went with the
latter since I figured it is a bit prettier in usage.

> I would also change implicit declarations into an error, I see
> you have an throw statement for that but commented out.

Yes, the main reason is so the ref returns don't do range
violation when you are trying to do an assignment, due to the
above situation.

It would work with simple assignment:

dynobj.name; // throws
dynobj.name = 10; // works
dynobj.name; // still works

But complex assignment won't work there:

dynobj.name = someDelegate; // this won't work right, probably
// will segfault down the line if I don't throw at runtime over it

So my compromise was:

dynobj.name() = someDelegate; // uses the opAssign template
                              // which works well

But... if dynobj.name didn't already exist, the left hand side
of that would throw a range violation, getting a property that
doesn't exist.

That's why the exception is commented. If I required a .set()
method or something like that:

dynobj.set("name", whatever you want);

That would work, but it no longer looks like a dynamic language...



When the compiler progresses a little more (or maybe someone will
think of a nicer workaround), we can have the best of all worlds,
but for now this is the best I can do while keeping a mostly
dynamic language like appearance.


(Now, a related question here is weak typing in general. I'm
writing this to be very weakly typed - coercing all over the place.
Dynamic languages can throw a runtime exception on type mismatch,
but I want to basically mimic javascript here, which does not.
Besides, D itself is strongly typed - if you want strong types,
just use standard D types! Possibly including std.variant.)


More information about the Digitalmars-d mailing list