April 19, 2009
On Sat, 18 Apr 2009 14:05:30 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Steven Schveighoffer wrote:
>> 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.
>
> class X
> {
>    auto opDotExp(string fname, T...)(T args)
>    {
>       static if(fname == "blah")
>         return foo(args);
>       else static if(fname == "blither")
>         return bar(args);
>       else static assert(0, "Dunno how to "~fname);
>    }
> }

Yeah, I get that it can be done manually.  What I'm suggesting is that the compiler makes sure the static assert occurs if thbe result of compiling the template instance results in an empty function.  I look at it like adding methods to a class, you don't have to define which methods are not valid, all methods are by default invalid, only the ones you define are allowed.  With opDotExp, you are forced to define not only which calls to it are valid, but which ones aren't.  I'm saying, don't require defining which ones aren't, just like if you wanted to add methods to a class.  I'm sure I'm not explaining this perfectly...

For example, the swizzle example that has been brought up many times, you want to handle 256 possible method names, but there are an infinite number of method names.  You don't care about defining what to do in all situations, only in the situations you care about.  But without compiler help, you have to.

-Steve
April 19, 2009
On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Adam Burton wrote:
>> Andrei Alexandrescu wrote:
>>>> What about using something like '->' for dynamic calls instead of '.'?
>>> That's absolutely useless. If I have to write anything different from
>>> "." I might as well write "bloodyMaryBloodyMaryBloodyMary".
>>>
>>> Andrei
>> You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.
>
> I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering.
>
> The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.

Hm... the thought just occurred to me.

At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly?  For example, if you want to make a class/struct a range, why not just define the functions directly?  It seems odd to define them using opDotExp.

I can only see usages of either when you want to bind to dynamic data (e.g. fields in a database row) or when you want to define a vast number of functions where only a few will be used (i.e. Pascalize or swizzle example).

I'm not saying there aren't such usages, I just can't think of any myself.

-Steve
April 19, 2009
Michel Fortin wrote:
> On 2009-04-18 17:48:33 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
> 
>> Michel Fortin wrote:
>>> On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
>>>
>>>> I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?
>>>
>>> Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.
>>>
>>>
>>>> What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!
>>>
>>> Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.
>>>
>>>
>>>> And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!
>>>
>>> Wrong. Whether it's one way or another entirely depends on what your goals are.
>>
>> Wrong. It's impossible to pass a dynamic string as a static string, so the street is one way.
> 
> Indeed it's impossible using a template which requires a static string. And that's exactly the problem: some times you're supposed to make it work both ways, as I've explained in the rest of my post you've cut down. Did you read it?
> 
> I won't repeat everything, but here's the important part: not having it go both ways *is* an important drawback. And it doesn't go both ways only if opDotExp is a template.

I did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread.

You say: well if opDot were a template then a scripting language can't get to it because what it has is a dynamic string. Yes. That's why opDot does whatever static string processing and then forwards, if the design asks for it, to the dynamic function. opDot's participation is solely a syntax helper within D.


Andrei
April 19, 2009
Hello Adam,

> On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:
> 
>> The point of using "." is not syntactic convenience as much as the
>> ability of the Dynamic structure to work out of the box with
>> algorithms that use the standard notation.
>> 
> What if the dot remained exactly like it is now and the -> took
> the place of the dot in the proposal; regular method calls when
> possible and forwarded to opExtension (opDotExp needs a better name)
> when that fails?
> Thus your generic algorithm can use -> and work in all cases, and the
> dot operator remains the same as it is now.

Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.


April 19, 2009
Hello Michel,

> On 2009-04-18 17:48:33 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> said:
> 
>> Michel Fortin wrote:
>> 
>>> On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu
>>> <SeeWebsiteForEmail@erdani.org> said:
>>> 
>>>> I'm confused. Isn't it clear that at the moment we "have" the
>>>> ability to pass a function name as a runtime string?
>>>> 
>>> Indeed, you can pass the template argument as a runtime argument to
>>> another function. No misunderstanding here.
>>> 
>>>> What we're lacking is the ability to implement that using
>>>> reflection, but that's an entirely separated discussion!
>>>> 
>>> Runtime reflection lacking indeed, but wether runtime reflection is
>>> an entirely separated discussion depends on if what we're doing will
>>> get in the way of implementing it.
>>> 
>>>> And no, you're not supposed to forward from invoke(string,
>>>> Variant[]...) to opDotExp - it's precisely the other way around!
>>>> 
>>> Wrong. Whether it's one way or another entirely depends on what your
>>> goals are.
>>> 
>> Wrong. It's impossible to pass a dynamic string as a static string,
>> so the street is one way.
>> 
> Indeed it's impossible using a template which requires a static
> string. And that's exactly the problem: some times you're supposed to
> make it work both ways, as I've explained in the rest of my post
> you've cut down. Did you read it?
> 
> I won't repeat everything, but here's the important part: not having
> it go both ways *is* an important drawback. And it doesn't go both
> ways only if opDotExp is a template.
> 


If opDotExp is a template you can do:

struct S
{
    void NonStaticVersion(char[] name, args...) { ...}
    void opDotExp(char[] name, T...)(T t) { NonStaticVersion(name, t); }
}

if it is not a tamplate:

struct S
{
    void StaticVersion(char[] name, T ... )(T t) { ...}
    void opDotExp(char[] name, T...)
    {
       StaticVersion!(
                  /******** what goes here?? *********/
          )(T);
    }
}

you are either wrong, arguing something completely different than what everyone thinks you are or figured out how to do something everyone else thinks is impossible.


April 19, 2009
On 19/04/2009 01:22, BCS wrote:
> Hello Yigal,
>
>> On 18/04/2009 21:16, Andrei Alexandrescu wrote:
>>
>>> In the syntax
>>>
>>> a.b
>>>
>>> how would either of a and b be identified at runtime? I mean, you
>>> write the code somewhere and it gets compiled. It's not like you're
>>> reading "a.b" from the console and then call some eval() function
>>> against them.
>>>
>>> Andrei
>>>
>> what prevents D from having an eval function?
>> suppose someone modifies the DMD front-end to compile a string with
>> the
>> source code of a function in-memory, than this is processed by
>> something
>> based on DDL and what you get is an API call that takes source code in
>> a
>> string and returns a function pointer.
>
> Even then it is *still* going to be compile time. Just a compile time
> running at runtime... Ooohh, my heads's going to start hearing here in a
> bit.
>
>
No it won't. you will call a standard library API at *runtime* with a *runtime* string and get back a pointer to a function that you can call. in fact Some Lisp compilers implement eval() exactly like that.
you're thinking in C++ terms. try thinking in Lisp...
April 19, 2009
Steven Schveighoffer wrote:
> On Sat, 18 Apr 2009 14:05:30 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> Steven Schveighoffer wrote:
>>> 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.
>>
>> class X
>> {
>>    auto opDotExp(string fname, T...)(T args)
>>    {
>>       static if(fname == "blah")
>>         return foo(args);
>>       else static if(fname == "blither")
>>         return bar(args);
>>       else static assert(0, "Dunno how to "~fname);
>>    }
>> }
> 
> Yeah, I get that it can be done manually.  What I'm suggesting is that the compiler makes sure the static assert occurs if thbe result of compiling the template instance results in an empty function.  I look at it like adding methods to a class, you don't have to define which methods are not valid, all methods are by default invalid, only the ones you define are allowed.  With opDotExp, you are forced to define not only which calls to it are valid, but which ones aren't.  I'm saying, don't require defining which ones aren't, just like if you wanted to add methods to a class.  I'm sure I'm not explaining this perfectly...
> 
> For example, the swizzle example that has been brought up many times, you want to handle 256 possible method names, but there are an infinite number of method names.  You don't care about defining what to do in all situations, only in the situations you care about.  But without compiler help, you have to.
> 
> -Steve

You'll get a "missing return statement", except in the case where it's void. So it's only that one case where it's a problem.
April 19, 2009
Daniel Keep wrote:
> 
> bearophile wrote:
>> downs:
>>> bearophile:
>>>> But a static foreach (on a static data structure that has opApply) is not doable yet, I think.
>>> Foreach on a tuple is evaluated at compile-time.
>> Yes, that's the whole point of that Range!().
>> But you can't use that trick on an associative array, or a struct with OpApply, etc.
>>
>> Bye,
>> bearophile
> 
> And you can't have it outside a function like you can static if.  Also, there are various bugs relating to the values being iterated over sometimes kinda-but-not-really being compile-time constants.
> 
>   -- Daniel

Very true, but the _index_ should always be a constant.
April 19, 2009
On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Adam Burton wrote:
>>> Andrei Alexandrescu wrote:
>>>>> What about using something like '->' for dynamic calls instead of '.'?
>>>> That's absolutely useless. If I have to write anything different from
>>>> "." I might as well write "bloodyMaryBloodyMaryBloodyMary".
>>>>
>>>> Andrei
>>> You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.
>>
>> I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering.
>>
>> The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.
>
> Hm... the thought just occurred to me.
>
> At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly?  For example, if you want to make a class/struct a range, why not just define the functions directly?  It seems odd to define them using opDotExp.
>

Variant variantRange = someRange();
foreach (element; variantRange) {
   // ...
}

Variant forwards all the front/back/etc methods to an underlying range.
April 19, 2009
Adam Burton wrote:

> What about using something like '->' for dynamic calls instead of '.'? When
> you see '.' your safe in the knowledge that at a glance you know said method
> with said signature exists else the compiler will throw a paddy, when you
> see '->' you know that method call is evaluated at runtime. This has the
> added benefit that the same class can be used in compile time checking code
> and runtime.

One use I can see for this is the other opDotExp use that's been mentioned in this thread, namely:

struct s {
 opDotExp( string s ) { ... }
}

s obj;
auto command = readInput();
obj->command( ); // calls obj.opDotExp( command )

For message-passing, one could argue that <- would be better than ->, though there are ambiguity problems with that.

--
Simen