View mode: basic / threaded / horizontal-split · Log in · Help
June 20, 2009
Re: Ranges
== Quote from Yigal Chripun (yigal100@gmail.com)'s article
> Steve Teale wrote:
> > Robert Fraser Wrote:
> >
> >> Steve Teale wrote:
> >>> template isInputRange(R)
> >>> {
> >>>     enum bool isInputRange = is(typeof(
> >>>     {
> >>>         R r;             // can define a range object
> >>>         if (r.empty) {}  // can test for empty
> >>>         r.popFront;          // can invoke next
> >>>         auto h = r.front; // can get the front of the range
> >>>     }()));
> >>> }
> >>>
> >>> I can not possibly be the only D enthusiast who finds this completely
incomprehensible.
> >> Yeah, that one is a bit tricky, and what makes it worse is that it seems
> >> officially sanctioned by Walter/Andrei as the "right way" to check if a
> >> type supports some operations. Basically, if you have:
> >>
> >> is(typeof({ @@@ }()));
> >>
> >> this means "if I made a function containing @@@, would that function
> >> compile?". It's a hack which stems from the way the is expression works.
> >>
> >>> What is a range?
> >> As others have mentioned, it's just a struct (or other type) that
> >> happens to support certain operations.
> >
> > So does this mean that interfaces are just a tragic mistake. I'd always
thought that what you said was a pretty good description of what an interface is!
> >
> IMHO, duck-typing in D is a tragic mistake...  This should have been
> implemented with compile time interfaces.

Why?  Duck typing is incredibly flexible and simple, but the downside is that, in
its traditional implementation it's inefficient and only checkable at runtime.
The whole beauty of D's template system is that it allows something similar to
duck typing that is checked at compile time and has usually negligible (I won't
say zero since object file bloat can be practically significant in a few corner
cases) overhead.
June 20, 2009
Re: Ranges
bearophile wrote:
> (P.S.: Is Walter around still? He's pretty silent lately. Talking when he's not around looks quite academic).

He gave a D talk on Wednesday night. I get the feeling the next release 
is going to be something big.
June 20, 2009
Re: Ranges
dsimcha wrote:
> == Quote from Yigal Chripun (yigal100@gmail.com)'s article
>> Steve Teale wrote:
>>> Robert Fraser Wrote:
>>>
>>>> Steve Teale wrote:
>>>>> template isInputRange(R)
>>>>> {
>>>>>     enum bool isInputRange = is(typeof(
>>>>>     {
>>>>>         R r;             // can define a range object
>>>>>         if (r.empty) {}  // can test for empty
>>>>>         r.popFront;          // can invoke next
>>>>>         auto h = r.front; // can get the front of the range
>>>>>     }()));
>>>>> }
>>>>>
>>>>> I can not possibly be the only D enthusiast who finds this completely
> incomprehensible.
>>>> Yeah, that one is a bit tricky, and what makes it worse is that it seems
>>>> officially sanctioned by Walter/Andrei as the "right way" to check if a
>>>> type supports some operations. Basically, if you have:
>>>>
>>>> is(typeof({ @@@ }()));
>>>>
>>>> this means "if I made a function containing @@@, would that function
>>>> compile?". It's a hack which stems from the way the is expression works.
>>>>
>>>>> What is a range?
>>>> As others have mentioned, it's just a struct (or other type) that
>>>> happens to support certain operations.
>>> So does this mean that interfaces are just a tragic mistake. I'd always
> thought that what you said was a pretty good description of what an interface is!
>> IMHO, duck-typing in D is a tragic mistake...  This should have been
>> implemented with compile time interfaces.
> 
> Why?  Duck typing is incredibly flexible and simple, but the downside is that, in
> its traditional implementation it's inefficient and only checkable at runtime.
> The whole beauty of D's template system is that it allows something similar to
> duck typing that is checked at compile time and has usually negligible (I won't
> say zero since object file bloat can be practically significant in a few corner
> cases) overhead.

It sometimes makes up for a lack of an actual type system but it is not 
a true duck type system built into the language anyway as you have to go 
through the manual process of asking whether it is of a certain type 
through templates.
June 20, 2009
Re: Ranges
== Quote from Tim Matthews (tim.matthews7@gmail.com)'s article
> dsimcha wrote:
> > == Quote from Yigal Chripun (yigal100@gmail.com)'s article
> >> Steve Teale wrote:
> >>> Robert Fraser Wrote:
> >>>
> >>>> Steve Teale wrote:
> >>>>> template isInputRange(R)
> >>>>> {
> >>>>>     enum bool isInputRange = is(typeof(
> >>>>>     {
> >>>>>         R r;             // can define a range object
> >>>>>         if (r.empty) {}  // can test for empty
> >>>>>         r.popFront;          // can invoke next
> >>>>>         auto h = r.front; // can get the front of the range
> >>>>>     }()));
> >>>>> }
> >>>>>
> >>>>> I can not possibly be the only D enthusiast who finds this completely
> > incomprehensible.
> >>>> Yeah, that one is a bit tricky, and what makes it worse is that it seems
> >>>> officially sanctioned by Walter/Andrei as the "right way" to check if a
> >>>> type supports some operations. Basically, if you have:
> >>>>
> >>>> is(typeof({ @@@ }()));
> >>>>
> >>>> this means "if I made a function containing @@@, would that function
> >>>> compile?". It's a hack which stems from the way the is expression works.
> >>>>
> >>>>> What is a range?
> >>>> As others have mentioned, it's just a struct (or other type) that
> >>>> happens to support certain operations.
> >>> So does this mean that interfaces are just a tragic mistake. I'd always
> > thought that what you said was a pretty good description of what an interface is!
> >> IMHO, duck-typing in D is a tragic mistake...  This should have been
> >> implemented with compile time interfaces.
> >
> > Why?  Duck typing is incredibly flexible and simple, but the downside is that, in
> > its traditional implementation it's inefficient and only checkable at runtime.
> > The whole beauty of D's template system is that it allows something similar to
> > duck typing that is checked at compile time and has usually negligible (I won't
> > say zero since object file bloat can be practically significant in a few corner
> > cases) overhead.
> It sometimes makes up for a lack of an actual type system but it is not
> a true duck type system built into the language anyway as you have to go
> through the manual process of asking whether it is of a certain type
> through templates.

No you don't, constraints are just to improve overloading capabilities and provide
better error handling if you use a template wrong.
June 20, 2009
Re: Ranges
dsimcha:
> Abstract classes with only pure virtual functions.  In other words, basically
> under the hood, an interface is just the layout of a vtable.

Oh, right, sorry, my question really was "What are compile-time interfaces from the point of view of the compiler?"

Bye,
bearophile
June 20, 2009
Re: Ranges
dsimcha wrote:
> == Quote from bearophile (bearophileHUGS@lycos.com)'s article
>> Yigal Chripun:
>>> point in case, look how much
>>> unnecessary confusion Ranges cause which would be eliminated had D
>>> allowed for compile-time interfaces.
>> What are interfaces from the point of view of the compiler?
> 
> Abstract classes with only pure virtual functions.  In other words, basically
> under the hood, an interface is just the layout of a vtable.

That's run-time interfaces. compile-time interfaces are like C++ concepts.
> 
> This actually leads to a comment I want to make in the wider debate:  I personally
> find explicit interfaces really, really annoying and I think that duck typing is
> by far the most intuitive type system there is.  I used to program primarily in
> duck typed languages and resort to every kludge imaginable for speed.  What
> attracted me to D was that the templates and type inference are so powerful that I
> almost feel like it's still a duck typed language, but much faster and with more
> error checking.  I guess that's why I like ranges so much.

duck-typing has its benefits, that's for sure. it all boils down to is 
style issues I guess - do you prefer implicit or explicit interfaces.

either are fine by me, even though it seems to me that duck-typing is 
more of a dynamically typed language feature but maybe my feeling here 
is wrong.
either way, the language needs to be consistent about it in order to not 
confuse users unnecessarily.

> 
> Also, while the fact that you need interfaces to specify a vtable layout is an
> implementation detail, I would argue that, in close to the metal languages, it
> does more harm than good to try too hard to prevent implementation details from
> leaking into the language abstractions.  Otherwise, what would be the point of it
> being a close to the metal language?  The fact that, for templates, one does not
> need to specify vtable layouts and for OO you do justifies the asymmetry between
> templates and OO.  Interfaces for templates would just add boilerplate and make
> explicit something that is already implicitly knowable and checked at compile time
> anyhow.

here I disagree. it sometimes makes sense to let implementation details 
leak into your abstractions when you gain something by it, like 
performance (e.g. "Worse is better" principle) but I don't see how this 
applies here. what is there to gain by doing this compromise in this case?
there is no added performance since it's all compile-time, there is no 
additional flexibly like with run-time duck-typing.
June 20, 2009
Re: Ranges
Yigal Chripun wrote:

> Lutger wrote:
>> Yigal Chripun wrote:
>> ...
>>> IMHO, duck-typing in D is a tragic mistake...  This should have been
>>> implemented with compile time interfaces.
>> 
>> Care to provide arguments?
>> 
>> 
> 
> duck typing makes more sense in dynamic languages like Ruby which is
> famous for it.
> 
> in static languages I as a user prefer to trade flexibility due to
> duck-typing for compile time checks.
> 
> yes, at compile time, duck typing and (compile-time) interfaces are
> basically the same thing, but since the rest of the language uses formal
> interfaces, it is more consistent (and easier to understand) to use the
> same approach at compile-time as well. point in case, look how much
> unnecessary confusion Ranges cause which would be eliminated had D
> allowed for compile-time interfaces.
> i.e.
> Interface I { .. }
> struct S : I { ... }
> this is basically the same as C++ concepts only without redundant and
> confusing syntax.

Not sure what that would do, but C++ concepts are not exactly compile time 
interfaces. This is very important: in C++0X, a type T which satisfies the 
concept Comparable<T> does not implement the concept explicitly, whereas 
languages with explicit constraints on generics do require T to be inherited 
from IComparable. The consequence is a bit of bloat and more rigid demands 
on what is supposed to relax the inflexible regime of the static type 
system. This bloat and rigidity is also a cognitive burden in it's own 
right, for example when it requires workarounds when the system is not 
expressive enough. 

Concepts provide two benefits in this context: documentation and extra type 
checking for templates. But they do retain structural typing. In D, we 
already have this covered with template constraints.* If you look at 
std.range, this is exactly what you see: all the interfaces (and even 
semantics) are nicely named and documented explicitly. So would we have had 
compile time interfaces, they would add next to nothing about the 
documentation or understanding of ranges.

> templates are hard for users to understand and one of the main reasons
> for this is that templates are essentially a completely different
> language with different syntax and semantics which to me looks like
> mis-design.

I don't think it is hard to understand because of structural typing.  
Generics are inherently somewhat difficult in a static typing language, 
because of it's abstract nature. You don't have this problem in dynamic 
languages. (or you can't escape it, depending on your POV)

I don't agree that templates are a completely different language though. 
When used purely for parametric polymorphism, it does integrate nicely in 
the normal type system. When you do use it for meta-programming, which is 
relatively rare, then the above also applies: this is an inherently 
difficult way of programming. Just look at something like lisp where you can 
metaprogram in the same language. Does that make it easy to understand? Or 
CTFE and string mixins in D, same language, but it's also difficult. Adding 
more constraints can never solve the fact that humans don't easily grok 
programs which generate programs. 

* I don't think the extra type checking is done, but perhaps it could be.
June 20, 2009
Re: Ranges
Yigal Chripun wrote:

> dsimcha wrote:
>> == Quote from bearophile (bearophileHUGS@lycos.com)'s article
>>> Yigal Chripun:
>>>> point in case, look how much
>>>> unnecessary confusion Ranges cause which would be eliminated had D
>>>> allowed for compile-time interfaces.
>>> What are interfaces from the point of view of the compiler?
>> 
>> Abstract classes with only pure virtual functions.  In other words,
>> basically under the hood, an interface is just the layout of a vtable.
> 
> That's run-time interfaces. compile-time interfaces are like C++ concepts.
>> 
>> This actually leads to a comment I want to make in the wider debate:  I
>> personally find explicit interfaces really, really annoying and I think
>> that duck typing is
>> by far the most intuitive type system there is.  I used to program
>> primarily in
>> duck typed languages and resort to every kludge imaginable for speed. 
>> What attracted me to D was that the templates and type inference are so
>> powerful that I almost feel like it's still a duck typed language, but
>> much faster and with more
>> error checking.  I guess that's why I like ranges so much.
> 
> duck-typing has its benefits, that's for sure. it all boils down to is
> style issues I guess - do you prefer implicit or explicit interfaces.
> 
> either are fine by me, even though it seems to me that duck-typing is
> more of a dynamically typed language feature but maybe my feeling here
> is wrong.
> either way, the language needs to be consistent about it in order to not
> confuse users unnecessarily.

It's called structural typing in static languages which is almost the same 
but not quite. In duck typing, you can pass an object which does not 
implement the 'required' interface and this is not checked until a missing 
method is actually called. Another way of looking at it is that the 
interface is determined by the path of execution, which is even more 
flexible than structural typing.
June 20, 2009
Re: Ranges
Lutger wrote:
> Not sure what that would do, but C++ concepts are not exactly compile time 
> interfaces. This is very important: in C++0X, a type T which satisfies the 
> concept Comparable<T> does not implement the concept explicitly, whereas 
> languages with explicit constraints on generics do require T to be inherited 
> from IComparable. The consequence is a bit of bloat and more rigid demands 
> on what is supposed to relax the inflexible regime of the static type 
> system. This bloat and rigidity is also a cognitive burden in it's own 
> right, for example when it requires workarounds when the system is not 
> expressive enough. 

regarding the consequences - i agree that this is a bit more rigid. I 
don't see the bloat though. can you provide an example? can you also 
explain what kinds of workarounds are you talking about that would be 
required?

> 
> Concepts provide two benefits in this context: documentation and extra type 
> checking for templates. But they do retain structural typing. In D, we 
> already have this covered with template constraints.* If you look at 
> std.range, this is exactly what you see: all the interfaces (and even 
> semantics) are nicely named and documented explicitly. So would we have had 
> compile time interfaces, they would add next to nothing about the 
> documentation or understanding of ranges.
>  

there are several problems with the template constraints currently used.
1. the constraints are specified on the client code which means you need 
to either duplicate those constraints everywhere or call some template 
like isForwardRange manually to check that you got the correct type.
2. The syntax for this is completely alien and unreadable, at least for me.

documentations and type-checking are indeed the two main benefits I'd 
like to get.
the current way it is done with is() expression is unreadable. this 
needs to be specified IMO with the same (or almost the same) syntax as 
interfaces. I don't get why D needs two completely different syntaxes 
for the same thing (specifying an interface). this will give us a more 
readable documentation aspect.
the type-checking aspect of this is that the checks will be done on the 
template definition instead of the instantiation in the client code 
which will also prevent cases when bugs in a library template only 
manifest when the client programmer compiles *his* code. this happened 
to tango in the past.

>> templates are hard for users to understand and one of the main reasons
>> for this is that templates are essentially a completely different
>> language with different syntax and semantics which to me looks like
>> mis-design.
> 
> I don't think it is hard to understand because of structural typing.  
> Generics are inherently somewhat difficult in a static typing language, 
> because of it's abstract nature. You don't have this problem in dynamic 
> languages. (or you can't escape it, depending on your POV)
> 
> I don't agree that templates are a completely different language though. 
> When used purely for parametric polymorphism, it does integrate nicely in 
> the normal type system. When you do use it for meta-programming, which is 
> relatively rare, then the above also applies: this is an inherently 
> difficult way of programming. Just look at something like lisp where you can 
> metaprogram in the same language. Does that make it easy to understand? Or 
> CTFE and string mixins in D, same language, but it's also difficult. Adding 
> more constraints can never solve the fact that humans don't easily grok 
> programs which generate programs. 
> 
I was talking mostly about meta-programming and not parametric 
polymorphism.
I agree that it is harder to grok programs that generate programs. this 
is why it is so important IMO to make this as readable as possible.
to answer your question, lisp does make this _easier_ to understand 
compared to templates. D CTFE functions are much more readable than D 
templates.
while I agree that this is never trivial, it should not be made near 
impossible like it is in C++. an experienced user should be able to read 
the source of libs like Boost and STL and understand without much 
trouble what it does without being a C++ guru.

> * I don't think the extra type checking is done, but perhaps it could be.
> 

the distinction you make between generics with explicit constraints that 
require explicit inheritance and concepts is more of an implementation 
detail IMO.
the first uses run-time inheritance for this type checking.
what I'd prefer is the second implementation where the type-check is 
done at compile-time by means of structural typing but unlike C++ where 
it's optional I want it to be required so that the type-checking is 
performed on the definition and not on the instantiations.
does that make sense?
June 20, 2009
Re: Ranges
Lutger wrote:
> 
> It's called structural typing in static languages which is almost the same 
> but not quite. In duck typing, you can pass an object which does not 
> implement the 'required' interface and this is not checked until a missing 
> method is actually called. Another way of looking at it is that the 
> interface is determined by the path of execution, which is even more 
> flexible than structural typing.
>  

This is why i don't like it in static languages. I like my type system 
and want the compiler to check my code.
1 2 3
Top | Discussion index | About this forum | D home