|
Archives
D Programming
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
D.gnu
D
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
electronics
|
digitalmars.D - Re: Ranges
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!
Steve Teale wrote:
...
Robert Fraser Wrote:
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!
Could you explain why that makes interfaces a mistake? Interfaces (as in
classes implementing an interface) do provide dynamic polymorphism which
these compile time constraints (or 'concepts' in STL terms) don't.
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.
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?
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.
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?
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?
ignorance 'n' arrogance should do.
superdan 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?
ignorance 'n' arrogance should do.
Those I hold I high esteem, you convinced me.
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.
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.
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?
Bye,
bearophile
(P.S.: Is Walter around still? He's pretty silent lately. Talking when he's not
around looks quite academic).
== 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.
Abstract classes with only pure virtual functions. In other words, basically
under the hood, an interface is just the layout of a vtable.
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.
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.
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
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.
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.
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.
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.
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.
== Quote from Yigal Chripun (yigal100 gmail.com)'s article
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.
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.
Simplicity and DRY--you only need to specify what the compiler doesn't already
know.
dsimcha wrote:
== Quote from Yigal Chripun (yigal100 gmail.com)'s article
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.
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.
Simplicity and DRY--you only need to specify what the compiler doesn't already
know.
simplicity - have one syntax to remember instead of two.
DRY - concepts are already present and used, see the isXXXRange
templates. I didn't add anything beyond that.
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.
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.
yer didnt say why & this adds nutt'n'.
in static languages I as a user prefer to trade flexibility due to
duck-typing for compile time checks.
yer dunno what yer talking about do ya. d checks duck typed shit at compile
time.
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.
& how do ya figure tat I defines a type elementtype?
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.
2 me looks like yer in way over yer head.
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.
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.
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?
Yigal Chripun wrote:
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?
Ok, I sort of assumed you talked about explicit instantiation like in C#.
For any type that implements a clone operation for example, you have to
derive it from ICloneable if you are to use it as a generic parameter. In
addition, in your template, you have to explicitly bring all operations
under in an interface. (This is the bloat part). Now say I have a type from
another library that supports cloning, has the same interface as ICloneable,
but doesn't derive from it. You are forced to create a wrapper for it that
derives from ICloneable. (the workaround). Also, there is the complication
of what to do with arithmetic types.
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.
Yes that is the way to go I believe. Phobos already defines a lot of these
concepts so that makes it easier.
2. The syntax for this is completely alien and unreadable, at least for
me.
I agree, but this is a syntax detail. It has no bearing on the type system.
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.
I agree. This is point where concepts in C++ may prove more powerful.
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.
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?
I don't understand how you can have structural typing and at the same time
require explicit constraints. Maybe I'm missing something here? This was my
entire point: losing structural typing because of explicit generic
constraints is a bad thing.
Lutger wrote:
Ok, I sort of assumed you talked about explicit instantiation like in C#.
For any type that implements a clone operation for example, you have to
derive it from ICloneable if you are to use it as a generic parameter. In
addition, in your template, you have to explicitly bring all operations
under in an interface. (This is the bloat part). Now say I have a type from
another library that supports cloning, has the same interface as ICloneable,
but doesn't derive from it. You are forced to create a wrapper for it that
derives from ICloneable. (the workaround). Also, there is the complication
of what to do with arithmetic types.
the arithmetic types issue is not a problem in D since the relevant
operators are non-static in D.
I don't understand what's the bloat here. here's an example:
interface I { // you mean this interface is bloat ?
void func() ;
}
class C(T : I) {
...
}
regarding the workaround issue, we agreed already that verifying a type
against a concept is done structurally.
possible solutions are that identical concepts with different names are
implicitly castable to each other. the compiler will treat it similar to
aliases.
suppose that you got a type implementing the MyClonable interface which
is structurally identical to the standard ICloneable interface.
void foo(T : ICloneable) (T t) {...}
foo() should work with your type because for the compiler both
interfaces represent the same concept.
this restricts "duck-typing" to the concept level only.
another option is that instead of this being done by the compiler, the
programmer could specify this relation by:
alias MyConcept Iconcept;
// compile type-checks here for conformance and registers this identity
This idea probably can be further refined. I think My general direction
here is to have C++ concepts but with a *much* better syntax and more
tightly integrated into the type system. In C++ it feels like an
optional addon added as an after thought.
== 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
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?
happens to support certain operations.
So does this mean that interfaces are just a tragic mistake. I'd always
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.
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
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?
happens to support certain operations.
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.
== 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
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?
happens to support certain operations.
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.
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.
|
|