December 21, 2009
yigal chripun wrote:
> Lutger Wrote:
> 
>> Yigal Chripun wrote:
>>
>>> On 19/12/2009 01:31, Lutger wrote:
>>>> Yigal Chripun wrote:
>>>>
>>>>> On 18/12/2009 02:49, Tim Matthews wrote:
>>>>>> In a reddit reply: "The concept of templates in D is exactly the same
>>>>>> as in C++. There are minor technical differences, syntactic
>>>>>> differences, but it is essentially the same thing. I think that's
>>>>>> understandable since Digital Mars had a C++ compiler."
>>>>>>
>>>>>>
>> http://www.reddit.com/r/programming/comments/af511/ada_programming_generics/c0hcb04?context=3
>>>>>>
>>>>>> I have never touched ada but I doubt it is really has that much that
>>>>>> can't be done in D. I thought most (if not all) the problems with C++
>>>>>> were absent in D as this summary of the most common ones points out
>>>>>> http://www.digitalmars.com/d/2.0/templates-revisited.html.
>>>>>>
>>>>>> Your thoughts?
>>>>> I don't know Ada but I do agree with that reddit reply about c++ and D
>>>>> templates. D provides a better implementation of the exact same design,
>>>>> so it does fix many minor issues (implementation bugs). An example of
>>>>> this is the foo<bar<Class>>  construct that doesn't work because of the
>>>>> ">>" operator.
>>>>> However, using the same design obviously doesn't solve any of the deeper
>>>>> design problems and this design has many of those. An example of that is
>>>>> that templates are compiled as part of the client code. This forces a
>>>>> library writer to provide the source code (which might not be acceptable
>>>>> in commercial circumstances) but even more frustrating is the fact that
>>>>> template compilation bugs will also happen at the client.
>>>> Well yes, but the .NET design restrict the generic type to a specific
>>>> named interface in order to do type checking. You may find this a good
>>>> design choice, but others find it far more frustrating because this is
>>>> exactly what allows for a bit more flexibility in a statically typed
>>>> world. So it is not exactly a problem but rather a trade-off imho.
>>> The .Net implementation isn't perfect of course and has a few issues
>>> that should be resolved, one of these is the problem with using
>>> operators. requiring interfaces by itself isn't the problem though. The
>>> only drawback in this case is verbosity which isn't really a big deal
>>> for this.
>> The drawback is not verbosity but lack of structural typing. Suppose some  library has code that can be parametrized by IFoo and I have another library with a type that implements IBar, which satisfies IFoo but not explicitly so. Then what? Unless I have totally misunderstood .NET generics, I have to create some proxy object for IBar that implements IFoo just to satisfy the strong type checking of .NET generics. You could make the argument that this 'inconvenience' is a good thing, but I do think it is a bit more of a drawback than just increased verbosity.
> 
> The way I see it we have three options:
> 
> assume we have these definitions:
> interface I {...}
> class Foo : I {...}
> class Bar {...} // structurally compatible to I
> 
> template tp (I) {...}
> 
> 1) .Net nominative typing:
> tp!(Foo) // OK
> tp!(Bar) //not OK
> 
> 2) structural typing (similllar to Go?)
> tp!(Foo) // OK
> tp!(Bar) // also OK
> 
> 3) C++ style templates where the compatibility check is against the *body* of the template.
> 
> of the three above I think option 3 is the worst design and option 2 is my favorite design. I think that in reality you'll almost always want to define such an interface and I really can't think of any useful use cases for an unrestricted template parameter as in C++. 

You forgot option 4:

4) D2 constrained templates, where the condition is checked inside the template constraint.

This is more powerful than option 2, because:

(1) there are cases where you want MORE constraints than simply an interface; and (2) only a subset of constraints can be expressed as an interface.
Also a minor point: (3) interfaces don't work for built-in types.

Better still would be to make it impossible to compile a template which made use of a feature not provided through a constraint.

December 21, 2009
Don Wrote:
> > The way I see it we have three options:
> > 
> > assume we have these definitions:
> > interface I {...}
> > class Foo : I {...}
> > class Bar {...} // structurally compatible to I
> > 
> > template tp (I) {...}
> > 
> > 1) .Net nominative typing:
> > tp!(Foo) // OK
> > tp!(Bar) //not OK
> > 
> > 2) structural typing (similllar to Go?)
> > tp!(Foo) // OK
> > tp!(Bar) // also OK
> > 
> > 3) C++ style templates where the compatibility check is against the *body* of the template.
> > 
> > of the three above I think option 3 is the worst design and option 2 is my favorite design. I think that in reality you'll almost always want to define such an interface and I really can't think of any useful use cases for an unrestricted template parameter as in C++.
> 
> You forgot option 4:
> 
> 4) D2 constrained templates, where the condition is checked inside the template constraint.
> 
> This is more powerful than option 2, because:
> 
> (1) there are cases where you want MORE constraints than simply an
> interface; and (2) only a subset of constraints can be expressed as an
> interface.
> Also a minor point: (3) interfaces don't work for built-in types.
> 
> Better still would be to make it impossible to compile a template which made use of a feature not provided through a constraint.
> 

I wouldn't give that a sepoarate option number, IMO this is a variation on option2. regarding your notes:
when you can express the same concept in both ways, using an interface is esier to read & understand IMO. What about having a combination of the two designs? you define an interface and allow optionally defining additional constraints _on_the_interface_ instead of the template.
I think this complies with your points (1) and (2) and is better since you don't need to repeat the constraints at the call site (each template that uses that type needs to repeat the constraint).
even if you factor out the checks into a separate "isFoo" template you still need to add to each template declaration "if isFoo!(T)" which really should be done by the compiler instead.

regarding point(3) - this is orthogonal IMO. Ideally I'd like to see this distinction between builtin type and user defined one removed. int should be treated in the same manner as a user defined struct.

I completely agree about not compiling templates that use features not defined by constraints. This is in fact the main point I was trying to make in this thread.

December 21, 2009
yigal chripun wrote:
> 2) structural typing (similllar to Go?)
> tp!(Foo) // OK
> tp!(Bar) // also OK
> 
> 3) C++ style templates where the compatibility check is against the *body* of the template.
> 
> If you think of templates as functions the compiler executes, the difference between the last two options is that option 2 is staticly typed vs. option 3 which is dynamicaly typed. We all use D because we like static typing and there's no reasone to not extend this to compile-time as well.

I prefer to think of option 2 as explicitly typed while option 3 uses type inference.  Type inference is a good thing.



-- 
Rainer Deyke - rainerd@eldwood.com
December 21, 2009
Rainer Deyke Wrote:

> yigal chripun wrote:
> > 2) structural typing (similllar to Go?)
> > tp!(Foo) // OK
> > tp!(Bar) // also OK
> > 
> > 3) C++ style templates where the compatibility check is against the *body* of the template.
> > 
> > If you think of templates as functions the compiler executes, the difference between the last two options is that option 2 is staticly typed vs. option 3 which is dynamicaly typed. We all use D because we like static typing and there's no reasone to not extend this to compile-time as well.
> 
> I prefer to think of option 2 as explicitly typed while option 3 uses type inference.  Type inference is a good thing.
> 
> 
> 
> -- 
> Rainer Deyke - rainerd@eldwood.com

You might prefer that but it's incorrect. This is exactly equivalent to calling a Ruby function vs. a D function, only happens at the compiler's run-time instead your app's run-time. Errors that the compiler statically checks in D will only be caught at run-time in Ruby. In our case, this means that a user of a tempate can get compilation errors for the temple code itself.
December 21, 2009
yigal chripun wrote:
> Don Wrote:
>>> The way I see it we have three options:
>>>
>>> assume we have these definitions:
>>> interface I {...}
>>> class Foo : I {...}
>>> class Bar {...} // structurally compatible to I
>>>
>>> template tp (I) {...}
>>>
>>> 1) .Net nominative typing:
>>> tp!(Foo) // OK
>>> tp!(Bar) //not OK
>>>
>>> 2) structural typing (similllar to Go?)
>>> tp!(Foo) // OK
>>> tp!(Bar) // also OK
>>>
>>> 3) C++ style templates where the compatibility check is against the *body* of the template.
>>>
>>> of the three above I think option 3 is the worst design and option 2 is my favorite design. I think that in reality you'll almost always want to define such an interface and I really can't think of any useful use cases for an unrestricted template parameter as in C++. 
>> You forgot option 4:
>>
>> 4) D2 constrained templates, where the condition is checked inside the template constraint.
>>
>> This is more powerful than option 2, because:
>>
>> (1) there are cases where you want MORE constraints than simply an interface; and (2) only a subset of constraints can be expressed as an interface.
>> Also a minor point: (3) interfaces don't work for built-in types.
>>
>> Better still would be to make it impossible to compile a template which made use of a feature not provided through a constraint.
>>
> 
> I wouldn't give that a sepoarate option number, IMO this is a variation on option2. regarding your notes:
> when you can express the same concept in both ways, using an interface is esier to read & understand IMO. What about having a combination of the two designs? you define an interface and allow optionally defining additional constraints _on_the_interface_ instead of the template.
> I think this complies with your points (1) and (2) and is better since you don't need to repeat the constraints at the call site (each template that uses that type needs to repeat the constraint).

I don't think interfaces are flexible enough for that.
EG, how do you express that the type I must have a template function void baz!(X)(X x) ?
There's more to a type, than just a list of the virtual functions which it supports.

> even if you factor out the checks into a separate "isFoo" template you still need to add to each template declaration "if isFoo!(T)" which really should be done by the compiler instead.
> 
> regarding point(3) - this is orthogonal IMO. Ideally I'd like to see this distinction between builtin type and user defined one removed. int should be treated in the same manner as a user defined struct. 
> 
> I completely agree about not compiling templates that use features not defined by constraints. This is in fact the main point I was trying to make in this thread. 

The problem is, I'm not sure that it's feasible in general. At least, it's not obvious how to do it.

December 21, 2009
yigal chripun wrote:
> Rainer Deyke Wrote:
>> I prefer to think of option 2 as explicitly typed while option 3 uses type inference.  Type inference is a good thing.

> You might prefer that but it's incorrect.

It's not incorrect, it's another way of looking at the same thing. Structural type inference and compile-time dynamic typing are the same thing.


-- 
Rainer Deyke - rainerd@eldwood.com
December 21, 2009
Mon, 21 Dec 2009 04:05:01 -0700, Rainer Deyke wrote:

> yigal chripun wrote:
>> Rainer Deyke Wrote:
>>> I prefer to think of option 2 as explicitly typed while option 3 uses type inference.  Type inference is a good thing.
> 
>> You might prefer that but it's incorrect.
> 
> It's not incorrect, it's another way of looking at the same thing. Structural type inference and

> compile-time dynamic typing are the same
> thing.

Now that's a funny term.. you see

dynamic = runtime
static = compile-time

"compile type dynamic X" is a paradox. And so is "runtime static X"

Another note, dynamic types do have a compile time representation. On type system level the types all have a 'dynamic' type. Not much can be said about that unless e.g. pattern matching is used. Static structural types on the hand differ on compile time. They have some kind of structure. What type inference means in this context is that instead of

  typeof({type has members a and b}) foo = { a = 2, b = 3 }

you can say

  auto foo = { a = 2, b = 3 }

Now if you try to do

  auto foo = 1;
  foo = { a = 2, b = 3 }

you get a compile time error. With dynamic types that is not a compile time nor runtime error.
December 21, 2009
Don wrote:

> Lutger wrote:
...
>> http://en.wikipedia.org/wiki/Duck_typing#Structural_type_systems
> 
> That Wikipedia page doesn't any make sense to me. Is that *really* what
> duck typing is? If so, it's a complete misnomer. Because it's totally
> different to "if it looks like a duck, quacks like a duck, etc".
> If it looks like a duck now, but *didn't* look like a duck three minutes
> ago, you can be pretty sure it's NOT a duck!
> 
> Whereas what it calls "structural typing" follows the duck rule perfectly. There is no reasoning on that page as to why duck typing is restricted to dynamic languages.
> 
> There's far too much ideology in that page, it ought to get flagged as inappropriate. Eg this line near the top:
> 
> "Users of statically typed languages new to dynamically typed languages are usually tempted to .."
> 

Yes, but most of the (less academic) information on the web about type systems is like this. Hence the confusion about basic terms.

December 21, 2009
Mon, 21 Dec 2009 12:25:35 +0100, Lutger wrote:

> Don wrote:
> 
>> Lutger wrote:
> ...
>>> http://en.wikipedia.org/wiki/Duck_typing#Structural_type_systems
>> 
>> That Wikipedia page doesn't any make sense to me. Is that *really* what duck typing is? If so, it's a complete misnomer. Because it's totally different to "if it looks like a duck, quacks like a duck, etc". If it looks like a duck now, but *didn't* look like a duck three minutes ago, you can be pretty sure it's NOT a duck!
>> 
>> Whereas what it calls "structural typing" follows the duck rule perfectly. There is no reasoning on that page as to why duck typing is restricted to dynamic languages.
>> 
>> There's far too much ideology in that page, it ought to get flagged as inappropriate. Eg this line near the top:
>> 
>> "Users of statically typed languages new to dynamically typed languages are usually tempted to .."
>> 
>> 
> Yes, but most of the (less academic) information on the web about type systems is like this. Hence the confusion about basic terms.

The amateur opinions are often pure 100% crap - most ruby/python fanboys are just reinventing (NIH) the same wheel academic community already invented 50 years ago. Don't trust wikipedia on this.

http://www.pphsg.org/cdsmith/types.html http://www.reddit.com/r/compsci/comments/9zinc/ what_is_a_dynamic_type_system/

The book discussing type system essentials:

http://www.cis.upenn.edu/~bcpierce/tapl/ http://books.google.fi/books?id=ti6zoAC9Ph8C

Some related discussion:

http://lambda-the-ultimate.org/node/834 http://lambda-the-ultimate.org/node/1102 http://lambda-the-ultimate.org/node/1268 http://lambda-the-ultimate.org/node/2828 http://lambda-the-ultimate.org/node/2418 http://lambda-the-ultimate.org/node/1625 http://lambda-the-ultimate.org/node/1201
December 21, 2009
retard wrote:

<snip>

Thanks for links, that should help.