April 17, 2009
Christopher Wright wrote:
> Andrei Alexandrescu wrote:
>> Cool! I suggest the rewrite:
>>
>> c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args)
>>
>> That way you have the option of handling the method name statically or dynamically.
> 
> How would that allow you to handle the method name dynamically, if you're passing it as a template argument?
> 
> You mean that the *callee* can be dynamic. However, the *caller* cannot. 

Of course. It makes no sense to ask for integrated syntax with a variable string. Think of it for a minute.

> This would rarely be an issue, I grant, but:
> 
> Let's say you have a set of valid arguments for the opDotExp template. Why the hell aren't you writing individual methods?!
> 
> So opDotExp is nearly useless if you make the method name a template argument. The *only* uses are
> - blacklisting arguments, with compile-time errors
> - requiring that arguments follow a certain (regular) pattern, with compile-time errors
> - a way to get the __FUNCTION__ macro that's been requested several times and not yet implemented

I don't think I quite understand. Let me repeat: passing the string as a template gives you static+dynamic. Passing the string as a runtime value gives you dynamic. To clarify:

class Dynamo
{
    Variant call(string name, Variant[] args...)
    {
        ...
    }
    Variant opDotExp(string name, T...)(T args)
    {
        return call(name, variantArray(args));
    }
    ...
}

Now you can say:

Dynamo d;
d.foo();
string bar = chomp(readln);
d.call(bar);

Makes sense?

Andrei
April 17, 2009
Christopher Wright wrote:
> Andrei Alexandrescu wrote:
>> Yah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff.
>>
>> Andrei
> 
> 
> You suggest:
> 
> auto opDotExp(string name)(...)
> {
>     static if (name == "something")
>     {
>         code...
>     }
>     else
>     {
>         dynamic stuff
>     }
> }
> 
> That isn't very clear. Why not write it this way:
> 
> auto opDotExp(string name, ...)
> {
>     dynamic stuff
> }
> 
> auto something (...)
> {
>     code...
> }

It's a good question. opDotExp leaves more flexibility because it allows for a host of compile-time manipulations, e.g. decide to forward to a member etc. Also consider this (probably Nick will turn blue):

struct Pascalize(T)
{
    T m;
    auto opDotExp(string name, T...)(T args)
    {
        return mixin("m."~tolower(name))(args);
    }
}

struct S { void foo() { ... } }

Pascalize!S s;
s.foo(); // works
s.Foo(); // works too
s.fOo(); // yup, works again


Andrei
April 17, 2009
Nick Sabalausky wrote:
> "davidl" <davidl@nospam.org> wrote in message news:op.usje9ia3j5j59l@my-tomato...
>> The benefit is you don't need to write the call function,
> 
> ...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?

It's more work, but it lets you do other interesting things.

Prime example is one I mentioned earlier. Let's say we also get full RTTI implemented soon (either in a library [I'm working on it] or in the compiler). Then you can write a Variant type that you can call arbitrary methods on. Neat, huh?

Let's say you integrate D with a scripting language where you can add methods to an object at arbitrary times. Instead of writing:
scriptObj.invokeMethod("methodname", arguments);

You can instead write:
scriptObj.methodname(arguments);

This is a library type which has no business knowing about any methods that you have defined on scriptObj. Moreover, the alternative is to write this:

template ScriptMethod(string name)
{
	enum ScriptMethod = "void " ~ name ~ "(...) { return _vm.invokeMethod(_obj, \"" ~ name ~ \"" ~, _arguments, _argptr); }";
}

class ScriptObjWrapper
{
	// repeat this a few dozen times for each method
	mixin (ScriptMethod!("methodname"));
}



It's syntactic sugar, but it's really neat.
April 17, 2009
Andrei Alexandrescu wrote:
> I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well.

I don't think you can implement an interface with opDotExp, since it has a different signature.
April 17, 2009
Reply to Christopher,

> Andrei Alexandrescu wrote:
> 
>> Cool! I suggest the rewrite:
>> 
>> c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args)
>> 
>> That way you have the option of handling the method name statically
>> or dynamically.
>> 
> How would that allow you to handle the method name dynamically, if
> you're passing it as a template argument?
> 
> You mean that the *callee* can be dynamic. However, the *caller*
> cannot. This would rarely be an issue, I grant, but:
> 

the caller *can't* be dynamic, the calling code is known exactly at compile time. If you want to be able to call a function by name or by the normal syntax use:

void CallByName(char[] name, args...) {...}
void opDot(char[] name)(args...) { CallByName(name, args ...); } // one line, will get inlined if anything ever does.

> Let's say you have a set of valid arguments for the opDotExp template.
> Why the hell aren't you writing individual methods?!
> 

for one:

struct S(T)
{
  T* t;

  void opDot!(char[] name)(U u)
  {
       mixin("t." ~name~ "(v);");
  }
}

also haveing a large set of function where you can compute the meaning from the name:

void Foo(){...}
void FooBar(){...}
void Bar(){...}

//LogFoo
//LogFooBar
//LogBar

void opDot(char[] name)()
{
  static assert(name.length > 3 && name[0..3] == "Log")
  writelf("Calling "~ name[3..$]);
  mixin(name[3..$]~"();");
  writelf("Called "~ name[3..$]);
}


> So opDotExp is nearly useless if you make the method name a template
> argument. The *only* uses are
> - blacklisting arguments, with compile-time errors
> - requiring that arguments follow a certain (regular) pattern, with
> compile-time errors
> - a way to get the __FUNCTION__ macro that's been requested several
> times and not yet implemented


April 17, 2009
Nick Sabalausky wrote:
> "bearophile" <bearophileHUGS@lycos.com> wrote in message news:gsai34$1p9k$1@digitalmars.com...
>> Nick Sabalausky:
>>>> There are people who swear by the ability of adding methods at runtime and
>>>> changing the inheritance hierarchy dynamically. It makes for a very fluid
>>>> environment.
>>> Personally, I've always seen that as extremely sloppy and haphazard.
>> Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python.
> 
> Interesting, I didn't know that.
> 
>> Usually in such languages such things are less dangerous because the code contains lot of tests anyway.
> 
> See, that just sounds to me like the dynamic-ness is just creating extra work for less payoff. I'd rather have my compiler automatically guarantee correctness (when possible) than have to manually create even more tests than I'm already creating and *hope* that they catch all the problems.

Assuming that you are testing the logic of your application, you will trivially check things like accessing "legnth" rather than "length" -- under the assumption that these two methods would do different things. You would spend approximately no additional testing effort on opDotExp.

This doesn't hold if you are not writing tests.
April 17, 2009
Nick Sabalausky, el 17 de abril a las 17:45 me escribiste:
> >> There is a lot of black magic already doing on that makes much harder to see what's really going on with a piece of code (operator overloading?). If you don't like that, you should probably stick to C =)
> 
> There a point I keep bringing up that keeps getting ignored: the code-obscuring "black magic" that we already have provides real non-trivial benefits. I have yet to see an equally compelling case for the ability to call a dynamic method without an explicit dispatcher.

What do you call "non-trivial"?

Because I can see people seeing foreach a trivial benefit. After all you can allways write the for loop explicitly calling some methods.

> > It's more than just convenience; it's integration. Uniform form allows generic algorithms to operate on a variety of types. Somehow this argument keeps on being ignored in the discussion.
> >
> 
> That's not ignored at all, in fact I've already addressed it twice before: A reflection API that supports method invokation allows for generic calling of both static and dynamic functions.

The code for that would be so ugly I that nobody will agree to use it... I will be just a non-feature. Are you suggesting writting all generic code using something like traits(invoke, obj, "some_function", args) instead of obj.some_function(args) to be able to be use some dynamic method?

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
- is there a perl version of php?...
  cause i have cgi-bin access with perl and want to use php scripts.
April 17, 2009
Nick Sabalausky, el 17 de abril a las 16:48 me escribiste:
> "Leandro Lucarella" <llucax@gmail.com> wrote in message news:20090417191634.GA15139@homero.springfield.home...
> > Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:
> >>
> >> Sure, but what is the reason to need dynamic methods?  I'm just trying to understand the usefulness of it.
> >
> > RPC is an example that comes into mind
> >
> > There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =)
> 
> But is there any that can't be done with a dispatch function?

You can write anything even with brainfuck. There are no discussion about what's possible and what's not, we are just talking about syntax. I hope the "it can be done" argument stop poping out because we all agree that it's possible to do everything right now. The question is *how* you can do it.

> Besides, as I see it, the opDotExp-style syntax for calling a dynamic method is more limited because unless you're using a scripting language, you can't do:
> 
> auto foo = new Foo();
> char[] func = /* Get from user input */;
> foo.func(); // Call function the user specified

So?

> But you can do that with either a dispatch method or a reflection API that supports invokation.

I think the reflection API is needed too, but that's another topic. Both would be great.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
Cada movimiento que no se hace, es un movimiento que se pierde. Y cada movimiento que se pierde, se transforma en una mochila. Y las mochilas nos alejan, de nuestros amigos y nuestras amigas. Y nuestros amigos se transforman, en enemigos y en enemigas. Cada movimiento que se hace, es una mochila que se deja.
April 18, 2009
在 Sat, 18 Apr 2009 03:26:13 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:

> On Fri, 17 Apr 2009 15:08:12 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Nick Sabalausky wrote:
>>> "Steven Schveighoffer" <schveiguy@yahoo.com> wrote in message news:op.usjnzajzeav7ka@steves.networkengines.com...
>>>> On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a@a.a> wrote:
>>>>
>>>> My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.
>>>  That is a *very* good point, that hadn't even occured to me.
>>>
>>>> I think dynamic methods  have a very limited use, and probably aren't worth polluting the D  language for a few rare cases.
>>>>
>>>  Agreed.
>>>
>>>> When you know the API ahead of time,  you're almost always better off to have statically typed objects.  When  you don't know it ahead of time, well, I prefer the uglyness of seeing the  quoted strings to having the compiler just start trusting everything I do  ;)
>>>>
>>>  Agreed.
>>
>> I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well.
>>
>> If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language. (In fairness, static typing and OO have at best a tense marriage.)
>>
>> But anyway, my point is that it's good to be open-minded. If this conversation does nothing but leave us firmly with our heels in static-land, then we haven't gained anything. If we weren't used to static types we wouldn't be here. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal. I suggested Walter since a long time ago to support opDot!(string). He implemented the useless version (sigh) which was arguably much simpler and offered a cheap way to experiment. So I'm very happy it's back on the table, and with an implementation to boot. Congratulations David.
>
> I guess I don't mind the dynamic lookup of methods, but I really don't like the proposal to make it look exactly like a statically typed call.  To "hide" the fact that you are doing a dynamic lookup makes me worry about losing the invariants that I come to enjoy with statically typed methods, that is, if I see x.method(a, b, c), it means that the compiler has checked that I called that method correctly with the correctly typed information.
>
> I use C#'s runtime introspection all the time, and it makes for some really awesome code (things I wish D could do), but I still have to do things like
>
> Type[] argTypes = ...;
> object[] args = ...;
> x.GetType().GetMethod("myMethod", argTypes).Invoke(x, args);
>
> To have that simply cut down to:
>
> x.myMethod(a, b, c);
>

That's exactly what opDot can be capable of accomplishing. GetMethod is something which feeds the classobject with the method name the opDot woud like to handle and the fingerprint of the function.

> is a nifty experiment, but now I lost all ability to know how the compiler is interpreting that.  I bet D can do a much better job at runtime type information than C# due to the template system being so powerful, but I still want to know that I'm dynamically doing something versus statically.
>
> Something like:
>
> void foo(object x)
> {
>     x.invoke("myMethod", a, b, c);
> }
>
> where invoke is some method that uses the classinfo of x to look up the method would be freaking awesome ;)
>

This can also be done in D2 with my opDot proposal.

> -Steve



-- 
使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
April 18, 2009
在 Sat, 18 Apr 2009 03:45:43 +0800,Nick Sabalausky <a@a.a> 写道:

> "Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message
> news:gsak2p$1s8a$1@digitalmars.com...
>>
>> I think there's merit in binding via strings. It makes for very flexible
>> code that is future-proof, dynamic-linking-friendly, and hot-swappable
>> without recompiling (e.g. you don't need to recompile because you now
>> implement an interface etc.) Reflection is very useful as well.
>>
>> I think D can and should allow string lookup for its methods. It's a
>> low-complexity proposition that adds a very interesting tool to D's
>> arsenal.
>>
>
> That's a separate issue. I absolutely agree with the usefulness of being
> able to invoke static methods via a string identifier at runtime. But I
> think opDotExp is an extremely flawed way to do it. A much better way would
> be through a reflection mechanism:
>

The opDot func can be extremely restrictive by looking up a former added table which are function fingerprints registered by a method call like dynamo.addMethod("myfunc", &myfunc);
dynamo.Lenght or dynamo.mymethud would just result runtime exception, because you didn't register these functions.

> class Foo
> {
>     void bar() {}
> }
>
> auto foo = new Foo();
> traits(foo).func("bar").invoke();
>
> That way, you can have the benefits of runtime-string-identifier-invocation
> (and have it on *every* class/method), but without completely loosing
> compile-time checking on the members of every class which is capable of
> using it.
>
>> If anything, this agreed-fest shows that the rift between static typing
>> and dynamic typing is alive and well. I've seen many discussions in which
>> people were mystified how anyone gets anything done in a statically-typed
>> OO language.
>
> ...Doesn't necessarily mean both sides have valid points. Just that there's
> disagreement. Outside of diplomacy, it doesn't make any sense to agree with
> something you disagree with, or disagree with something you agree with, just
> for the sake a closing a rift. Better to just continue debating the issues
> with logical arguments. If nothing gets accomplished, well ok, fine, but so
> what? That's a lot better than coming to hasty-but-wrong agreement just for
> the sake of agreement.
>
> I guess what I'm saying is, people coming to an agreement is all fine and
> dandy, but the most important thing is to arrive at the *correct* agreement.
> If one group of people insist that "2+2=0" and another group insists that
> "2+2=10", then it's far better to keep analyzing and debating until "2+2=4"
> is discovered and proven than to say "let's all be happy!" and hastily agree
> that "2+2=5". Again, outside of diplomacy, people disagreeing is not the
> real problem, the real problem is that the best answer either hasn't been
> found or hasn't been unquestionably shown to be best.
>
>



-- 
使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/