June 21, 2006
Walter Bright wrote:

> 85: It can't be made to work, because an interface handle is different from a class handle. It doesn't work in C++, either, for the same reasons.

But it can be made to work, because an interface handle could be the same as a class handle. It works that way in Java, and is _far_ more useful, even if performance of method calls is reduced slightly.

But we talked about that already, and I don't suppose you'll change your mind this time..


xs0
June 21, 2006
Walter Bright wrote:
> Jari-Matti Mäkelä wrote:
>> David Medlock wrote:
>>> New delegate syntax looks great, can't wait to try it!
>> 
>> Excellent. It's good to see that Walter likes many of the good features in Ruby. Some Java/C++ -fanboys might say that they're pure syntactic sugar, but trust me - they have lost their sanity long time ago ;)
> 
> It's possible to go too far with conciseness (APL and Perl show that!), but in general being able to write what you mean with a minimum of fuss makes for a more productive language.

I like most of the new features in D. They are both efficient and productive and still quite easy to use. Other than array literals and some polishing of interfaces, imports and templates there is not much left to make D the next king in it's class. I'm more than grateful for the experience I've had exploring the world of D.

-- 
Jari-Matti
June 21, 2006
Lionello Lunesu wrote:
> BCS wrote:
> 
>> Chris Miller wrote:
>>
>>> On Tue, 20 Jun 2006 02:03:08 -0400, Walter Bright  <newshound@digitalmars.com> wrote:
>>>
>>>> Mostly bug fixes.
>>>>
>>>> http://www.digitalmars.com/d/changelog.html
>>>
>>>
>>>
>>>
>>> Wow, that new literal delegate syntax is crazy but I like it.
>>>
>> [...]
>>
>> Ohhhh fun!! Try finding the bug in this one (ignore the hints).
> 
> 
> -snip-
> 
> It seems to work just fine here? Prints 2, exactly what I expected :)
> 
>  L.


if about 4 typos are removes it becomes this and returns 1.

<code>
#import std.stdio;
#void main()
#{
#    writef(fn,\n);
#}
#
#int fn()
#{
#  int baz()
#  {
#    return 6;
#  }
#
#  void figNewton( int i, int delegate()fnp=&baz, int k=3, int l=0)
#  {
#  }
#  int w;
#
#  /+
#  figNewton(9,
#  {
#    return 1;
#  },
#  w = (1+3),
#  doNothing);
#  +/
#
#  figNewton(9);
#  {
#    return 1;
#  };
#  w = (1+3);
#  doNothing);
#
#  return 2;
#}
#int doNothing(){return 1;}
</code>

Another not so obfuscated one is this:

#import std.stdio;
#void main()
#{
#  for(int i=0; i<10; i++)
#  (cast(void delegate())
#  {
#    writef("foo");
#    return;
#  }
#  )();
#}

The point is that there could end up being some confusion as to weather something is a function or just a block. I think that the last rule gos a bit to far. Typing in the "()" doesn't cost much and adds a bunch as far as readability goes.


FunctionLiteral
	function Typeopt ( ArgumentList )opt FunctionBody
	delegate Typeopt ( ArgumentList )opt FunctionBody
	( ArgumentList ) FunctionBody
>>	FunctionBody
June 21, 2006
xs0 wrote:
> Walter Bright wrote:
> 
>> 85: It can't be made to work, because an interface handle is different from a class handle. It doesn't work in C++, either, for the same reasons.
> 
> But it can be made to work, because an interface handle could be the same as a class handle. It works that way in Java, and is _far_ more useful, even if performance of method calls is reduced slightly.
> 
> But we talked about that already, and I don't suppose you'll change your mind this time..

Java makes it "work" by doing runtime manipulation of interface/class handles whenever they are used. This is too inefficient for a native compiled language.

Consider this:

  int can be implicitly converted to long.
  Therefore, shouldn't int[] be usable as a long[]?

It's an exactly analogous situation.
June 21, 2006
Walter Bright wrote:
> xs0 wrote:
> 
>> Walter Bright wrote:
>>
>>> 85: It can't be made to work, because an interface handle is different from a class handle. It doesn't work in C++, either, for the same reasons.
>>
>>
>> But it can be made to work, because an interface handle could be the same as a class handle. It works that way in Java, and is _far_ more useful, even if performance of method calls is reduced slightly.
>>
>> But we talked about that already, and I don't suppose you'll change your mind this time..
> 
> 
> Java makes it "work" by doing runtime manipulation of interface/class handles whenever they are used. This is too inefficient for a native compiled language.
> 
> Consider this:
> 
>   int can be implicitly converted to long.
>   Therefore, shouldn't int[] be usable as a long[]?
> 
> It's an exactly analogous situation.


A user code solution could be used:

T[] castArray(F, T)(F[] array)
{
	T[] ret = new T[array.length];
	foreach(i,e;array)
	{
			// this is from memory, but you get the picture
		static if(is(T : Object))
			(e!is null) ? ret[i]=e; ? ret[i]=null;
		else
			ret[i]=e;
	}
	return ret;
}


void main()
{
	const static int[] from = [1,2,3,4,5,6,7,8,9];

	long[] to = castArray!(int, long)(from);
}
June 21, 2006
Walter Bright wrote:
> xs0 wrote:
>> Walter Bright wrote:
>>
>>> 85: It can't be made to work, because an interface handle is different from a class handle. It doesn't work in C++, either, for the same reasons.
>>
>> But it can be made to work, because an interface handle could be the same as a class handle. It works that way in Java, and is _far_ more useful, even if performance of method calls is reduced slightly.
>>
>> But we talked about that already, and I don't suppose you'll change your mind this time..
> 
> Java makes it "work" by doing runtime manipulation of interface/class handles whenever they are used.

Well, I think it's quite irrelevant what Java does (and the same goes for C++*), the question is what is a better option, where we seem to disagree.

> This is too inefficient for a native compiled language.

I (still) think you're over-exaggerating the efficiency issue, because the difference is not that large in reality. For anything but the simplest methods the speed penalty is practically negligible (I measured it), and it's not the simplest methods that most time is spent on, I'd say.

And you could use the same argument against virtual methods, but you still implemented them.

> Consider this:
> 
>   int can be implicitly converted to long.
>   Therefore, shouldn't int[] be usable as a long[]?
> 
> It's an exactly analogous situation.

No, it isn't. int is of a different "class" than long, while an interface reference and a class reference point to exactly the same object.

You also seem to miss the reduced complexity of implementation (a stated goal I believe). With a simple double lookup, interfaces can be handled in a single place, and I'd guess you could implement that very easily just by faking another calling convention.

On the other hand, if interface references point to a different address than class references, you need to store offsets somewhere, have to modify the address on every call, need to handle implicit conversions when passing function boundaries, etc. etc.


xs0

*) Note that C++ supports MI, meaning double lookup would hurt every method call. Otoh, in D we'd get to keep the speed of non-interface calls.
June 22, 2006
>> Consider this:
>> 
>>   int can be implicitly converted to long.
>>   Therefore, shouldn't int[] be usable as a long[]?
>> 
>> It's an exactly analogous situation.
>
>No, it isn't. int is of a different "class" than long, while an interface reference and a class reference point to exactly the same object.
>
>You also seem to miss the reduced complexity of implementation (a stated goal I believe). With a simple double lookup, interfaces can be handled in a single place, and I'd guess you could implement that very easily just by faking another calling convention.

Can you explain more what you mean by double lookup? I'm not aware of that technique.

>On the other hand, if interface references point to a different address than class references, you need to store offsets somewhere, have to modify the address on every call, need to handle implicit conversions when passing function boundaries, etc. etc.

This technique I'm used to. It's called thunking and I believe it's the standard way of implementing MI and/or interfaces. That is, when a class implements an interface method it makes a thunk to adjust the 'this' pointer before calling the actual class method. So when you have an interface A and class C and call a method f in A that is implemented in C the slot in the vtable for f (which takes an A) calls the thunk to adjust the A to a C and then the thunk jumps to the method (which takes a C).

-Ben


June 22, 2006
>> Consider this:
>> 
>>   int can be implicitly converted to long.
>>   Therefore, shouldn't int[] be usable as a long[]?
>> 
>> It's an exactly analogous situation.
>
>No, it isn't. int is of a different "class" than long, while an interface reference and a class reference point to exactly the same object.
>
>You also seem to miss the reduced complexity of implementation (a stated goal I believe). With a simple double lookup, interfaces can be handled in a single place, and I'd guess you could implement that very easily just by faking another calling convention.

Can you explain more what you mean by double lookup? I'm not aware of that technique.

>On the other hand, if interface references point to a different address than class references, you need to store offsets somewhere, have to modify the address on every call, need to handle implicit conversions when passing function boundaries, etc. etc.

This technique I'm used to. It's called thunking and I believe it's the standard way of implementing MI and/or interfaces. That is, when a class implements an interface method it makes a thunk to adjust the 'this' pointer before calling the actual class method. So when you have an interface A and class C and call a method f in A that is implemented in C the slot in the vtable for f (which takes an A) calls the thunk to adjust the A to a C and then the thunk jumps to the method (which takes a C).

-Ben


June 22, 2006
In article <e7bv51$9lp$1@digitaldaemon.com>, Walter Bright says...

[...]
>Consider this:
>
>   int can be implicitly converted to long.
>   Therefore, shouldn't int[] be usable as a long[]?
>
>It's an exactly analogous situation.

I agree.
To make it simple you can do like this:

template copycast (T : T[])
{
  T[] copycast (X) (X[] array)
  {
    T[] retVal = new T[array.length];
    foreach (int i, X elem; array)
    {
      retVal[i] = cast(T) elem;
    }
    return retVal;
  }
}

int main()
{
  int[] a = new int[10];
  long[] al = copycast!(long[]) (a);

  interface I {  }
  class A : I {  }
  A[] array = new A[10];
  I[] dest = copycast!(I[]) (array);

  return 0;
}

Ciao

---
http://www.mariottini.net/roberto/
June 22, 2006
BenHinkle wrote:
>>> Consider this:
>>>
>>>   int can be implicitly converted to long.
>>>   Therefore, shouldn't int[] be usable as a long[]?
>>>
>>> It's an exactly analogous situation.
>> No, it isn't. int is of a different "class" than long, while an interface reference and a class reference point to exactly the same object.
>>
>> You also seem to miss the reduced complexity of implementation (a stated goal I believe). With a simple double lookup, interfaces can be handled in a single place, and I'd guess you could implement that very easily just by faking another calling convention.
> 
> Can you explain more what you mean by double lookup? I'm not aware of that
> technique.

It's very simple :)

> iref.someFunction(...) // iref is an interface reference

becomes

> iref.getVtbl(SomeInterface.classinfo)[2](iref, ...)

instead of the current

> iref.someFunction(iref-offset, ...)


I tested speed of various calling methods with
http://www.xs0.com/d/ifaces.d.html

and here are the results I get:

              Normal:             12165450 / sec
   Through interface:             11764706 / sec
   Lookup every time:              9580379 / sec
    Optimized lookup:             13390466 / sec
    Static functions:             13224015 / sec

The number is function calls / second.

With a function of any significant complexity, the differences would be even smaller, and even here it's just around 20% in the worst case. And if a simple observation* is implemented in the optimizer, the speed loss in fact becomes speed gain (ok, in reality it would also be implemented for non-interface methods, so the speed would end up the same).

*) if the object reference doesn't change neither can the function pointer


>> On the other hand, if interface references point to a different address than class references, you need to store offsets somewhere, have to modify the address on every call, need to handle implicit conversions when passing function boundaries, etc. etc.
> 
> This technique I'm used to. It's called thunking and I believe it's the standard
> way of implementing MI and/or interfaces. That is, when a class implements an
> interface method it makes a thunk to adjust the 'this' pointer before calling
> the actual class method. So when you have an interface A and class C and call a
> method f in A that is implemented in C the slot in the vtable for f (which takes
> an A) calls the thunk to adjust the A to a C and then the thunk jumps to the
> method (which takes a C).

Well, I think there's a significant difference between MI and interfaces in that interfaces only allow methods, while with MI you also have fields to think of. Having to basically make a function call for each field access would indeed be too inefficient, but it's not the same case with methods, because the call itself usually takes only a (very) small part of total method execution time.


xs0