Fully dynamic d by opDotExp overloading
Denis Koroskin
2korden at gmail.com
Sat Apr 18 13:45:53 PDT 2009
On Sat, 18 Apr 2009 21:43:15 +0400, Steven Schveighoffer <schveiguy at yahoo.com> wrote:
> On Fri, 17 Apr 2009 23:43:22 -0400, Steven Schveighoffer
> <schveiguy at yahoo.com> wrote:
>
>> On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer
>> <schveiguy at yahoo.com> wrote:
>>
>>> Andrei wrote:
>>>> We are discussing a language extension. That language extension will
>>>> allow a type to choose flexibility in defining methods dynamically,
>>>> while being otherwise integrated syntactically with the current
>>>> values. This has advantages, but also alters the expectations.
>>>
>>> As long as it identifies what can be dynamic and what cannot. I can't
>>> imagine Walter will go for this with his strict view of hijacking.
>>
>> Let me add that if there was a way for syntax to easily allow for
>> unintentional calls to be translated to compile-time errors, I think
>> this would be a workable solution.
>>
>> For example, I don't have any problem with your Pascalize example,
>> because you have not removed any static typing from the code (i.e. no
>> unexpected noops or exceptions are built in). If there were some way
>> to enforce this, then I think it would be a usable idea. For instance,
>> if you only allow CTFE to specify a function that is called when
>> certain strings are passed in, I don't have a problem with that,
>> because you are simply dispatching the data to strongly typed functions
>> at compile time, which provide compile-time errors when you mess up.
>
> I gave this a lot of thought, and I think here is a possible solution:
>
> the main reason I'm hesitant on this idea is because of code like this:
>
> class X
> {
> auto opDotExp(string fname, T...)(T args)
> {
> if(fname == "blah")
> return foo(args);
> else if(fname == "blither")
> return bar(args);
> // else, nothing happens
> }
> }
>
> Which leaves code open to lots of compiled code that doesn't do the
> right thing (or throws some runtime exception). What would be nice is
> if the default behavior is what statically bound functions do, that is,
> compile error, and only let the cases be handled which the author
> expects to handle.
>
> For that, I think if we make the following rule, we will see much less
> code that is poorly written, and I think dynamic functions will be
> feasible:
>
> If the compiler can determine during compilation of an opDotExp instance
> that the resulting function is empty, then it is a compiler error, just
> like if you tried to call a function that doesn't exist. This behavior
> can be overridden by putting a return statement in an otherwise empty
> function.
>
> So for example, the above can be statically determined to compile to
> nothing if fname is not "blah" or "blither", and therefore would be a
> compiler error. Of course, if you call functions that are not
> statically evaluable, then you are back to the danger of truly dynamic
> bindings, but that would make sense for things that cannot be evaluated
> at compile time.
>
> What do you think?
>
> -Steve
Here is an example of a more sophisticated opDotExp use case that relies on its templated version:
A Wrapper struct is a simple wrapper around any arbitrary data. It fully encapsulates the underlying object and never gives it away.
A simple example is a reference-counter. You want this object to allow any operations on it, but you want to disallow raw object access.
"alias this" is very unsafe in this respect.
struct Wrapper(T)
{
private T t;
this(ref T obj) {
_obj = obj; // capture. I believe there must be a better way to transfer ownership, but I don't know how
}
auto opDotExp(string fname, T...)(T args)
{
return t.opDotExp!(fname, T)(args); // how do you forward a call? Do all types have an implicit opDotExp method, i.e. for any given type T, T.bar == T.opDotExp("bar")?
}
}
class Foo
{
int bar() { return 42; }
void baz(int n) { ... }
// ...
}
auto o = Wrapper(new Foo());
int x = o.bar();
o.baz = -1;
Foo f = o; // disallowed!
It works by referring all the methods to an underlying object. You'll get a compile-time error if it doesn't have such method or property:
o.call(); // Error: no such method
That's a great functionality, and you can't do it if opDotExp was a runtime method.
More information about the Digitalmars-d
mailing list