April 17, 2009
Nick Sabalausky, el 17 de abril a las 16:38 me escribiste:
> "Adam D. Ruppe" <destructionator@gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d@puremagic.com...
> > On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:
> >> What
> >> opDotExp is, is a tool of only occasional use that provides only a small
> >> benefit, *and* ends up destroying a much more important tool:
> >> compile-time
> >> checking on a class's members.
> >
> > Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator?
> >
> > If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway.
> >
> 
> The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function.

This is like foreach. In C a for loop is a for loop, you are never calling a bizarre member function when looping. When you see code using foreach, you have to go look the variable definition to see if it's a real array to see what the looping is doing.

Do we need foreach? No, it's just syntax sugar. But I think it makes life much more easier...


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 =)

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
April 17, 2009
Leandro Lucarella wrote:
> Nick Sabalausky, el 17 de abril a las 16:38 me escribiste:
>> "Adam D. Ruppe" <destructionator@gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d@puremagic.com...
>>> On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:
>>>> What
>>>> opDotExp is, is a tool of only occasional use that provides only a small
>>>> benefit, *and* ends up destroying a much more important tool: compile-time
>>>> checking on a class's members.
>>> Wouldn't the compile time checking remain the same on any class except
>>> the Variant (or whatever) which implements the new operator?
>>>
>>> If it is constrained to one type, the destruction seems like it would be
>>> acceptable. You can't trust much on a Variant at compile time anyway.
>>>
>> The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function. 
> 
> This is like foreach. In C a for loop is a for loop, you are never calling
> a bizarre member function when looping. When you see code using foreach,
> you have to go look the variable definition to see if it's a real array to
> see what the looping is doing.
> 
> Do we need foreach? No, it's just syntax sugar. But I think it makes life
> much more easier...
> 
> 
> 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 =)
> 

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.

Andrei
April 17, 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsapu0$24ei$2@digitalmars.com...
>
> Then why overloadable operators? Just write a function call and call it a day.

Overloadable operators and opDotExp both sacrifice code transparency. In
that regard, they're the same. But
overloadable operators provide non-trivial benefit. From what I've seen,
opDotExp doesn't.

The only real argument for opDotExp I've seen so far is for things like DB/DDL/haxe.xml.Fast. I've make counter-arguments to that, but I have yet to see those counter-arguments actually refuted. Instead I keep getting a bunch of "use a dynamic lang and you'll see" hand-waving. And, for the record, I have spent a good deal of time using dynamic langs.

> Also, while we're at it, let's prefix all function calls with the word "call" so it's clear that a call is going on. (Some language did that after all.)
>

Another apples-and-oranges. In C-style languages, getting rid of "call" does not sacrifice code transparency (unlike op overloading and opDotExp) since function calls can be easily identified at a glance by an identifier followed by parens (and calls/declarations can be easily identified by whether or not they're preceded by a type). As a side note, this is one of the reasons I hate D's parens-are-optional-when-there's-no-arguments feature.

> The fact of the matter is you're in this discussion only to reaffirm a preconceived opinion. Instead of reiterating your arguments, it might be of great use to listen to those made by others.
>

Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.


April 17, 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsapl6$24ei$1@digitalmars.com...
> Steven Schveighoffer wrote:
>>
>> Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?
>
> You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range.
>
> Would you like ranges that work very different from built-in arrays, and everybody to special-case around that?
>

That's an inadequate comparison. We *can* make arrays and ranges usable in the same way. But opDotExp cannot make dynamic calls usable in the same way as static calls, because one of the rules of static method invokation is that trying to call a non-existant function results in a compile-time error. The best opDotExp can do it make dynamic calls *seem* the same which is deceptive.

If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities:

1. Make attempts to invokation a non-existant static function a runtime
error (obviously a bad idea).
or
2. Provide a *secondary* syntax to invoke a method that works for both
static and dynamic. Such as through a reflection api:

traits(new Foo()).invokeMethod("bar");


April 17, 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsaqe6$25kf$1@digitalmars.com...
> Leandro Lucarella wrote:
>>
>> This is like foreach. In C a for loop is a for loop, you are never
>> calling
>> a bizarre member function when looping. When you see code using foreach,
>> you have to go look the variable definition to see if it's a real array
>> to
>> see what the looping is doing.
>>
>> Do we need foreach? No, it's just syntax sugar. But I think it makes life much more easier...
>>
>>
>> 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.

> 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.


April 17, 2009
Nick Sabalausky wrote:
> Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.

Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing.

Andrei
April 17, 2009
Nick Sabalausky wrote:
> "Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsapl6$24ei$1@digitalmars.com...
>> Steven Schveighoffer wrote:
>>> Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?
>> You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range.
>>
>> Would you like ranges that work very different from built-in arrays, and everybody to special-case around that?
>>
> 
> That's an inadequate comparison. We *can* make arrays and ranges usable in the same way. But opDotExp cannot make dynamic calls usable in the same way as static calls, because one of the rules of static method invokation is that trying to call a non-existant function results in a compile-time error. The best opDotExp can do it make dynamic calls *seem* the same which is deceptive.

Au contraire, it's a very adequate comparison. We changed the language to support ranges/arrays uniformly. Here, I'll paste your argument with the appropriate changes:

====
But globals acting as members cannot make arrays usable in the same way
as user-defined types, because one of the rules of arrays is that trying to call a non-existant member function on an array results in a compile-time error. The best your rule can do it make nonmember calls *seem* the same which is deceptive.
====

> If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities:
> 
> 1. Make attempts to invokation a non-existant static function a runtime error (obviously a bad idea).
> or
> 2. Provide a *secondary* syntax to invoke a method that works for both static and dynamic. Such as through a reflection api:
> 
> traits(new Foo()).invokeMethod("bar");

If I want to write an algorithm that calls "bar" twice, it should be:

void twix(T)(T value)
{
   value.bar();
   value.bar();
}

NOT

void twix(T)(T value)
{
    static if (isDynamicType!T)
    {
        value.invokeMethod("bar");
        value.invokeMethod("bar");
    }
    else
    {
        value.bar();
        value.bar();
    }
}

Please at least acknowledge that you are in receipt of this argument.

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.


Andrei

April 17, 2009
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:

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
April 17, 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsamou$204u$1@digitalmars.com...
> Nick Sabalausky wrote:
>> 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.
>
> I was expecting this objection. I think it's not based because unifying syntax is a major part of adding such a feature. If we get to dynamic invocation but we can't go the last mile, we failed. Look at IDispatch-based programming in C++ vs. interpreted languages.
>

Can you clarify what you mean here?

>> ...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.
>
> Of course. One thing that suggests the righteousness is not necessarily on your side is that plenty knowledgeable, intelligent, credible people use and advocate dynamic typing. Asserting that they simply miss the point is a bit tenuous.
>

No one's infallible no matter how smart or capable (and there's been plenty of examples of supposedy brilliant people doing crazy things like joining wacko cults, etc). I'd be wary of treading so close to [inverse] ad hominem territory. (Besides, aren't there not plenty of "knowledgeable...etc" people on the static-typing side? Like you and Walter? ;) )

>> 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.
>
> I'm with you, and in wake of my frequent postings I guess it's pretty known by now that nothing makes me more annoying than knowing 100% I'm right :o). Certainly I'm not one who "agrees to disagree" and I'm glad you aren't either.
>

:)


April 17, 2009
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...
}