digitalmars.D - auto ref
- Walter Bright (14/14) Dec 15 2009 There's a need in generic code to have a function take a parameter by
- Mikhail Dahl (9/23) Dec 15 2009 Just to confirm (I'm just getting into D, so I don't know much about the...
- Walter Bright (3/10) Dec 15 2009 From the return statement in the body of the function.
- Mikhail Dahl (3/13) Dec 16 2009 Ah yeah sorry, it's too obvious. That's what happens at 8am when you've
- Walter Bright (4/6) Dec 16 2009 I know the feeling well. Well enough that I don't even bother trying to
- KennyTM~ (2/16) Dec 16 2009 auto const?
- Jason House (2/3) Dec 16 2009 I was wondering the same thing.
- Walter Bright (2/7) Dec 16 2009 The const transport thing is, unfortunately, a very different problem.
- Jason House (2/10) Dec 16 2009 Of course, but it may still go through bikeshed issues. This morning I r...
- Steven Schveighoffer (18/31) Dec 16 2009 I think one of the problems is that ref is a storage class, so it's easy...
- Michel Fortin (30/45) Dec 16 2009 Since this is just a special kind of const, it could be called "const^"
- Michel Fortin (6/8) Dec 16 2009 Bad editing. That should be "const?". Sorry if it confuses anyone.
- =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= (3/9) Dec 16 2009 You know, just Object means Object or a derived type. That's what
- Michel Fortin (9/21) Dec 17 2009 The idea is to be able to say in the function signature that the same
- KennyTM~ (2/19) Dec 17 2009 T func(T)(T o);
- Michel Fortin (9/32) Dec 17 2009 That would work, unless you want a virtual function.
- Nick Sabalausky (4/33) Dec 17 2009 Pardon my ignorance, but why is it that templated functions can't be
- dsimcha (24/26) Dec 17 2009 This is an unfortunate consequence of compilation model leaking out into...
- Bill Baxter (49/75) Dec 17 2009 u don't
- Andrei Alexandrescu (6/46) Dec 17 2009 This notion of templates "restricted enough" to be virtual has been
- Steven Schveighoffer (16/22) Dec 17 2009 Technically, the vconst functions provide one other feature -- implicit ...
- bearophile (20/22) Dec 17 2009 "All problems in computer science can be solved by another level of indi...
- Bill Baxter (66/86) Dec 18 2009 ation.<
- bearophile (6/16) Dec 18 2009 I think Walter has abandoned that idea, for never specified implementati...
- Nick Sabalausky (9/44) Dec 18 2009 But we already can't instantiate templates without the source anyway, so...
- dsimcha (4/55) Dec 18 2009 To clarify, the requirement is somewhat stronger than having the source....
- Steven Schveighoffer (11/48) Dec 17 2009 This can never work. a const?(Object) is const during the function
- Michel Fortin (25/57) Dec 17 2009 I'm not sure why, but I always forget that const(Object) is not
- Steven Schveighoffer (16/61) Dec 17 2009 That doesn't do anything :) It may as well be written:
- Simen kjaeraas (7/30) Dec 16 2009 auto const auto ref Foo bar( auto const auto ref Foo arg ) {
- Leandro Lucarella (13/45) Dec 17 2009 Just call "auto const auto ref" "auto auto":
- Simen kjaeraas (9/47) Dec 17 2009 Even better, with return type inference:
There's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }
Dec 15 2009
On 16/12/2009 07:18, Walter Bright wrote:There's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }Just to confirm (I'm just getting into D, so I don't know much about the language, still learning), but the idea is to apply 'auto' not only to types but also to storage classes? As in 'automatically apply ref in the case of lvalue'? If so I'm a little confused by 'auto ref foo(...' - if auto ref here is also simply an 'apply ref in the case of lvalue', then where is the return type being inferred from? Dahl
Dec 15 2009
Mikhail Dahl wrote:Just to confirm (I'm just getting into D, so I don't know much about the language, still learning), but the idea is to apply 'auto' not only to types but also to storage classes? As in 'automatically apply ref in the case of lvalue'?Yes, exactly.If so I'm a little confused by 'auto ref foo(...' - if auto ref here is also simply an 'apply ref in the case of lvalue', then where is the return type being inferred from?From the return statement in the body of the function.
Dec 15 2009
On 16/12/2009 07:41, Walter Bright wrote:Mikhail Dahl wrote:Ah yeah sorry, it's too obvious. That's what happens at 8am when you've had no sleep.Just to confirm (I'm just getting into D, so I don't know much about the language, still learning), but the idea is to apply 'auto' not only to types but also to storage classes? As in 'automatically apply ref in the case of lvalue'?Yes, exactly.If so I'm a little confused by 'auto ref foo(...' - if auto ref here is also simply an 'apply ref in the case of lvalue', then where is the return type being inferred from?From the return statement in the body of the function.
Dec 16 2009
Mikhail Dahl wrote:That's what happens at 8am when you've had no sleep.I know the feeling well. Well enough that I don't even bother trying to code when I feel that way, as after I get some sleep I have to unwind all those "great ideas" I had when overtired.
Dec 16 2009
On Dec 16, 09 15:18, Walter Bright wrote:There's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }auto const?
Dec 16 2009
KennyTM~ Wrote:auto const?I was wondering the same thing.
Dec 16 2009
Jason House wrote:KennyTM~ Wrote:The const transport thing is, unfortunately, a very different problem.auto const?I was wondering the same thing.
Dec 16 2009
Walter Bright Wrote:Jason House wrote:Of course, but it may still go through bikeshed issues. This morning I read about inout, return, vconst, aconst, sameconst, autoconst, auto const, and bikeshed. At least one of those was in jest :) auto const isn't that bad, and you obviously liked auto ref...KennyTM~ Wrote:The const transport thing is, unfortunately, a very different problem.auto const?I was wondering the same thing.
Dec 16 2009
On Wed, 16 Dec 2009 16:46:14 -0500, Jason House <jason.james.house gmail.com> wrote:Walter Bright Wrote:I think one of the problems is that ref is a storage class, so it's easy to insert another storage class on top of it. With the const transport issue, the identifier has to be a type constructor, and needs to decorate types in the same way const can. i.e.: identifier(int)[] but ref isn't like this, you don't see: ref(int)[] So if you used auto const, what does this mean: auto const(int)[] It looks strange to me. Remember that you will see this not only in parameter types but in stack variable declarations. This also makes auto a type constructor, which it is not currently. I think we have enough multi-meaning keywords. I don't really care what the keyword turns out to be, but I think it needs to be a single keyword. -SteveJason House wrote:Of course, but it may still go through bikeshed issues. This morning I read about inout, return, vconst, aconst, sameconst, autoconst, auto const, and bikeshed. At least one of those was in jest :) auto const isn't that bad, and you obviously liked auto ref...KennyTM~ Wrote:The const transport thing is, unfortunately, a very different problem.auto const?I was wondering the same thing.
Dec 16 2009
On 2009-12-16 16:46:14 -0500, Jason House <jason.james.house gmail.com> said:Walter Bright Wrote:Since this is just a special kind of const, it could be called "const^" (const or a derived constness): const?(Object) func(const?(Object) o) { return o; } The interesting thing about it, beside not taking a keyword, is that it can scale in the future if we need to add many distinct constness to the same function signature: const?(Object) func(const?(Object) o, const?2(Object) o2, out const?2(Object) o3) { o3 = o2; return o; } Not that you'd need that often, but if it does becomes necessary in the future we'll still have some options. Furthermore, the concept could be extended to any type. This could be useful with class hierarchies: Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type. Yeah, that breaks the proposed syntax for nullable types... just too bad. If that's really a problem we could use ^ instead. -- Michel Fortin michel.fortin michelf.com http://michelf.com/Jason House wrote:Of course, but it may still go through bikeshed issues. This morning I read about inout, return, vconst, aconst, sameconst, autoconst, auto const, and bikeshed. At least one of those was in jest :) auto const isn't that bad, and you obviously liked auto ref...KennyTM~ Wrote:The const transport thing is, unfortunately, a very different problem.auto const?I was wondering the same thing.
Dec 16 2009
On 2009-12-16 19:05:09 -0500, Michel Fortin <michel.fortin michelf.com> said:Since this is just a special kind of const, it could be called "const^" (const or a derived constness):Bad editing. That should be "const?". Sorry if it confuses anyone. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 16 2009
On 12/17/2009 01:05 AM, Michel Fortin wrote:Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.You know, just Object means Object or a derived type. That's what inheritance is.
Dec 16 2009
On 2009-12-17 01:57:50 -0500, Pelle Månsson <pelle.mansson gmail.com> said:On 12/17/2009 01:05 AM, Michel Fortin wrote:The idea is to be able to say in the function signature that the same type is returned, avoiding a cast that would be unnecessary otherwise. It's the same principle as for "const?", or "inout". But you're right that my definition isn't very good. -- Michel Fortin michel.fortin michelf.com http://michelf.com/Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.You know, just Object means Object or a derived type. That's what inheritance is.
Dec 17 2009
On Dec 17, 09 19:44, Michel Fortin wrote:On 2009-12-17 01:57:50 -0500, Pelle MÃ¥nsson <pelle.mansson gmail.com> said:T func(T)(T o);On 12/17/2009 01:05 AM, Michel Fortin wrote:The idea is to be able to say in the function signature that the same type is returned, avoiding a cast that would be unnecessary otherwise. It's the same principle as for "const?", or "inout". But you're right that my definition isn't very good.Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.You know, just Object means Object or a derived type. That's what inheritance is.
Dec 17 2009
On 2009-12-17 07:09:57 -0500, KennyTM~ <kennytm gmail.com> said:On Dec 17, 09 19:44, Michel Fortin wrote:That would work, unless you want a virtual function. If templates were always an acceptable solution, the whole discussion about passing const qualifiers from the argument to the return value wouldn't be of any use either. -- Michel Fortin michel.fortin michelf.com http://michelf.com/On 2009-12-17 01:57:50 -0500, Pelle Månsson <pelle.mansson gmail.com> said:T func(T)(T o);On 12/17/2009 01:05 AM, Michel Fortin wrote:The idea is to be able to say in the function signature that the same type is returned, avoiding a cast that would be unnecessary otherwise. It's the same principle as for "const?", or "inout". But you're right that my definition isn't very good.Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.You know, just Object means Object or a derived type. That's what inheritance is.
Dec 17 2009
"Michel Fortin" <michel.fortin michelf.com> wrote in message news:hgd9jb$26v9$1 digitalmars.com...On 2009-12-17 07:09:57 -0500, KennyTM~ <kennytm gmail.com> said:Pardon my ignorance, but why is it that templated functions can't be virtual?On Dec 17, 09 19:44, Michel Fortin wrote:That would work, unless you want a virtual function. If templates were always an acceptable solution, the whole discussion about passing const qualifiers from the argument to the return value wouldn't be of any use either.On 2009-12-17 01:57:50 -0500, Pelle Månsson <pelle.mansson gmail.com> said:T func(T)(T o);On 12/17/2009 01:05 AM, Michel Fortin wrote:The idea is to be able to say in the function signature that the same type is returned, avoiding a cast that would be unnecessary otherwise. It's the same principle as for "const?", or "inout". But you're right that my definition isn't very good.Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.You know, just Object means Object or a derived type. That's what inheritance is.
Dec 17 2009
== Quote from Nick Sabalausky (a a.a)'s articlePardon my ignorance, but why is it that templated functions can't be virtual?This is an unfortunate consequence of compilation model leaking out into language design. You're supposed to be able to subclass a base class even if you don't have the full source code to it. Let's say we have: class A { void doStuff(T)(T arg) {} } class B : A { void doStuff(T)(T arg) { writeln("In B."); } } And then we do: B b = new B; b.doStuff(1); The instantiation of B.doStuff() with an int would require that the vtable for A be updated to include doStuff!(int). This is not possible if we also allow base classes to be compiled separately from derived classes and the code that uses the derived class. The only solution I see would be to completely get rid of separate compilation. For my personal use, since most of my projects are under 10k lines and take a negligible amount of time to compile anyhow, I'd be in favor of this. However, for larger projects or projects that require things to work based only on interface, without access to the full source code, this is probably impractical.
Dec 17 2009
On Thu, Dec 17, 2009 at 9:28 AM, dsimcha <dsimcha yahoo.com> wrote:=3D=3D Quote from Nick Sabalausky (a a.a)'s articlelanguagePardon my ignorance, but why is it that templated functions can't be virtual?This is an unfortunate consequence of compilation model leaking out into =design. =A0You're supposed to be able to subclass a base class even if yo=u don'thave the full source code to it. =A0Let's say we have: class A { =A0 =A0void doStuff(T)(T arg) {} } class B : A { =A0 =A0void doStuff(T)(T arg) { =A0 =A0 =A0 =A0writeln("In B."); =A0 =A0} } And then we do: B b =3D new B; b.doStuff(1); The instantiation of B.doStuff() with an int would require that the vtabl=e for Abe updated to include doStuff!(int). =A0This is not possible if we also a=llow baseclasses to be compiled separately from derived classes and the code that =uses thederived class. The only solution I see would be to completely get rid of separate compil=ation.For my personal use, since most of my projects are under 10k lines and ta=ke anegligible amount of time to compile anyhow, I'd be in favor of this. =A0=However,for larger projects or projects that require things to work based only on interface, without access to the full source code, this is probably impra=ctical. This 'auto ref' stuff and the multi-flavor 'vconst' functions are basically templates with a known list of instantiations (ref /no-ref, and const/immutable/plain) In theory there's no reason you couldn't allow templates to also create virtual functions, if you limit yourself to listing the possible instantiations up front. It feels like we may be missing out on a more general construct here that could embrace all these cases via some extension to template syntax. I'm reminded of how Go interfaces do the job of both specifying that a function is a template and checking constraints on use. In D-ish syntax, Go uses something like this: interface Foo { ... } void doSomething(Foo f, int x) { ... } To mean something like template CheckIfIsFoo!(T) { ... } void doSomething(T)(T f, int x) if (CheckIfIsFoo!(T)) { ... } The advantage is that the compiler can offer better error messages about what part of the check fails, and the syntax is cleaned up significantly (less repetition, less proliferation of parentheses). Maybe a similar approach could be used to separate the specification of these alternatives into pseudo-types that can then be used as parameters. Like static interface VConst(T) { constnessOf(T) is in [const, immutable, !const]; } VConst!(Bar) doSomething(VConst!(Bar) b, int y) {...} static interface MaybeRef(T) { refnessOf(T) is in [ref, !ref]; } MaybeRef!(Bar) doSomethingElse(MaybeRef!(Bar) b, int y) { ... } Anyway, the more I look at standard C++ and D template syntax the more I think that Go is onto something. Yeh, there are some generic container-like templated types where T really can be any type (which Go inexcusably ignores), but very often there are some restrictions on T that are important enough and common enough that they deserve some support with a terse syntax. --bb
Dec 17 2009
Bill Baxter wrote:On Thu, Dec 17, 2009 at 9:28 AM, dsimcha <dsimcha yahoo.com> wrote:This notion of templates "restricted enough" to be virtual has been intensively discussed a couple of years ago between Walter, Bartosz and myself. Back then it was much less clear where to draw the line, but right now the idea is well worth revisiting. Andrei== Quote from Nick Sabalausky (a a.a)'s articleThis 'auto ref' stuff and the multi-flavor 'vconst' functions are basically templates with a known list of instantiations (ref /no-ref, and const/immutable/plain) In theory there's no reason you couldn't allow templates to also create virtual functions, if you limit yourself to listing the possible instantiations up front.Pardon my ignorance, but why is it that templated functions can't be virtual?This is an unfortunate consequence of compilation model leaking out into language design. You're supposed to be able to subclass a base class even if you don't have the full source code to it. Let's say we have: class A { void doStuff(T)(T arg) {} } class B : A { void doStuff(T)(T arg) { writeln("In B."); } } And then we do: B b = new B; b.doStuff(1); The instantiation of B.doStuff() with an int would require that the vtable for A be updated to include doStuff!(int). This is not possible if we also allow base classes to be compiled separately from derived classes and the code that uses the derived class. The only solution I see would be to completely get rid of separate compilation. For my personal use, since most of my projects are under 10k lines and take a negligible amount of time to compile anyhow, I'd be in favor of this. However, for larger projects or projects that require things to work based only on interface, without access to the full source code, this is probably impractical.
Dec 17 2009
On Thu, 17 Dec 2009 13:03:51 -0500, Bill Baxter <wbaxter gmail.com> wrote:This 'auto ref' stuff and the multi-flavor 'vconst' functions are basically templates with a known list of instantiations (ref /no-ref, and const/immutable/plain) In theory there's no reason you couldn't allow templates to also create virtual functions, if you limit yourself to listing the possible instantiations up front.Technically, the vconst functions provide one other feature -- implicit casting back to the correct type. You can't support that with templates, and still have the compiler ensure const is obeyed during the function all with a function signature. Also, there is only ever a single vconst function, not 3^n overloaded ones. But I agree with allowing a restricted template to be able to be virtual. One recent discussion that applies here is templatized operator overloading -- wouldn't it be nice if: opBinary(op : "+")(T rhs) {...} could be a virtual function? That gives us immediate support for virtual functions without the hoaky: opBinary(op : "+")(T rhs) {return opAdd(rhs);} mixin boilerplate. (BTW, this was Denis Koroshin's idea, not mine) -Steve
Dec 17 2009
dsimcha:The only solution I see would be to completely get rid of separate compilation.<"All problems in computer science can be solved by another level of indirection;" -- David Wheeler But that also slows code down a little :-) -------------------- Bill Baxter: Static interfaces are an easy idea, it was discussed some weeks ago, and probably it's not too much hard to implement in the language. I like them enough, but they don't add that much to the template constraints already present, so it's mostly a duplication of syntax and semantics. So I am not sure they are a good idea.static interface VConst(T) {constnessOf(T) is in [const, immutable, !const]; } VConst!(Bar) doSomething(VConst!(Bar) b, int y) {...} static interface MaybeRef(T) { refnessOf(T) is in [ref, !ref]; } MaybeRef!(Bar) doSomethingElse(MaybeRef!(Bar) b, int y) { ... }< Walter has just added traits to perform this, so I think this is already doable, with __trait/meta. and template constraints. The opIn_r defined for arrays is something that D2 must eventually have, there's no doubt about this. But "is in", followed by an array of those modifiers is currently impossible (you may create a tuple of templates, where each template tests for constness, etc). Maybe in future you can create an array of annotations: [ const, immutable, notConst] Bye, bearophile
Dec 17 2009
On Thu, Dec 17, 2009 at 11:41 AM, bearophile <bearophileHUGS lycos.com> wro= te:dsimcha:ation.<The only solution I see would be to completely get rid of separate compil="All problems in computer science can be solved by another level of indir=ection;"-- David Wheeler But that also slows code down a little :-) -------------------- Bill Baxter: Static interfaces are an easy idea, it was discussed some weeks ago, and =probably it's not too much hard to implement in the language. I like them e= nough, but they don't add that much to the template constraints already pre= sent, so it's mostly a duplication of syntax and semantics. So I am not sur= e they are a good idea. My reason for bringing them up was to say that perhaps they could be carried beyond that simple idea.doable, with __trait/meta. and template constraints.static interface VConst(T) {=A0 constnessOf(T) is in [const, immutable, !const]; } VConst!(Bar) doSomething(VConst!(Bar) b, int y) {...} static interface MaybeRef(T) { =A0 refnessOf(T) is in [ref, !ref]; } MaybeRef!(Bar) doSomethingElse(MaybeRef!(Bar) b, int y) { ... }< Walter has just added traits to perform this, so I think this is already =The opIn_r defined for arrays is something that D2 must eventually have, =there's no doubt about this.But "is in", followed by an array of those modifiers is currently impossi=ble (you may create a tuple of templates, where each template tests for con= stness, etc). Maybe in future you can create an array of annotations:[ const, immutable, notConst]Yeh, I know what I wrote is impossible now. Just putting the idea out there because it seems like we're heading for a place where we solve the problem of generating multiple versions of a function in three completely different ways (auto ref, vconst and of course templates) [four if you count generating them with string mixins]. I don't know what the proper generalization is, but I think if you try to keep templates the way they are while generalizing them to handle these cases you will end up with an unworkable notation nightmare. I like the way Go static interfaces refactor template specifications to simplify the overall syntax. In WalterAndrei.pdf from the D conference there was talk of static parameters and of unifying regular functions and templates. The Go approach basically accomplishes that by associating a symbol with all the template specification baggage. Then just by using that symbol in the parameter list of an ordinary-looking function, the compiler can tell not only 'hey we've got a template' but also what types of constraints apply. In a sense, current templates are analogous to structures that require you to spell out the members of the struct every time you use one. For structs we can do: struct Complex { float re; float im; }; Complex addComplex(Complex a, Complex b); But imagine if you had to write that always as template isComplex(T) { enum isComplex =3D __traits(hasMember,T,"re") && __traits(hasMember,T,"im") && typeof(T.init.im =3D=3D float) && typeof(T.init.re =3D= =3D float); } T addComplex(T)(T a, T b) if (IsComplex!(T)) { ... } The current system forces you to do that the instant your constraint becomes more complex than "a struct that has these members of these types in this particular order". Instead, Go encodes the complexity in a reusable symbol that acts like a type name, but it contains richer, more generic information than a regular type. A big thing lacking is that Go doesn't give you a way to express constraints between types. Like with: T index(T,S)(T[S] x, S y) { ... } But I think you could devise a way to encompass such cases. Maybe something like: static interface Indexable { Indexed :=3D Indexable[Index]; } Indexable.Indexed index(Indexable x, Indexable.Index y) { ... } (Note this is more general than the above T[S] template which only matches built-in AA's) This is clearly too much for D2 to swallow at this point. But I think it's worth thinking about whether there may be a significantly better way to specify parametrized types and constraints on them than what C++ and D use. --bb
Dec 18 2009
Bill Baxter:I don't know what the proper generalization is, but I think if you try to keep templates the way they are while generalizing them to handle these cases you will end up with an unworkable notation nightmare.It's not easy to design such large changes up-front (Andrei has for example done it with Ranges, but only few people have enough brain to do that and produce a final result that's useful in practice), so I think the design strategy used here is: try to generalize templates to address those cases, produce a too much high castle of cards that you can see is unstable, then try to fix the mess redesigning using a more clean design. The key here is to keep the D3 design process flexible enough, so you can fix design mistakes along the way ;-) It's an iterative process of generalization & abstraction.In WalterAndrei.pdf from the D conference there was talk of static parameters and of unifying regular functions and templates.I think Walter has abandoned that idea, for never specified implementation difficulties. I'd like to know more about those difficulties (but I agree that if an implementation is too much hard to do compared to the gains it gives, then it's better to abandon it).But I think it's worth thinking about whether there may be a significantly better way to specify parametrized types and constraints on them than what C++ and D use.Of course. But you may need to implement a more powerful type system to do that. Bye, bearophile
Dec 18 2009
"dsimcha" <dsimcha yahoo.com> wrote in message news:hgdpn2$t1c$1 digitalmars.com...== Quote from Nick Sabalausky (a a.a)'s articleBut we already can't instantiate templates without the source anyway, so I don't see how doing that vtable update for A would create any additional requirements on source availability that we don't already have, regardless of whether or not the function is virtual. Either way, the issue of "Do I need to provide the source?" still boils down to just "Am I defining a public template?" and is not at all dependent on "Is this going to be externally subclassed?".Pardon my ignorance, but why is it that templated functions can't be virtual?This is an unfortunate consequence of compilation model leaking out into language design. You're supposed to be able to subclass a base class even if you don't have the full source code to it. Let's say we have: class A { void doStuff(T)(T arg) {} } class B : A { void doStuff(T)(T arg) { writeln("In B."); } } And then we do: B b = new B; b.doStuff(1); The instantiation of B.doStuff() with an int would require that the vtable for A be updated to include doStuff!(int). This is not possible if we also allow base classes to be compiled separately from derived classes and the code that uses the derived class. The only solution I see would be to completely get rid of separate compilation. For my personal use, since most of my projects are under 10k lines and take a negligible amount of time to compile anyhow, I'd be in favor of this. However, for larger projects or projects that require things to work based only on interface, without access to the full source code, this is probably impractical.
Dec 18 2009
== Quote from Nick Sabalausky (a a.a)'s article"dsimcha" <dsimcha yahoo.com> wrote in message news:hgdpn2$t1c$1 digitalmars.com...To clarify, the requirement is somewhat stronger than having the source. A, B, and all code that instantiates template methods of A or B would probably all have to be compiled as one compilation unit to get the vtable layout right.== Quote from Nick Sabalausky (a a.a)'s articleBut we already can't instantiate templates without the source anyway, so I don't see how doing that vtable update for A would create any additional requirements on source availability that we don't already have, regardless of whether or not the function is virtual. Either way, the issue of "Do I need to provide the source?" still boils down to just "Am I defining a public template?" and is not at all dependent on "Is this going to be externally subclassed?".Pardon my ignorance, but why is it that templated functions can't be virtual?This is an unfortunate consequence of compilation model leaking out into language design. You're supposed to be able to subclass a base class even if you don't have the full source code to it. Let's say we have: class A { void doStuff(T)(T arg) {} } class B : A { void doStuff(T)(T arg) { writeln("In B."); } } And then we do: B b = new B; b.doStuff(1); The instantiation of B.doStuff() with an int would require that the vtable for A be updated to include doStuff!(int). This is not possible if we also allow base classes to be compiled separately from derived classes and the code that uses the derived class. The only solution I see would be to completely get rid of separate compilation. For my personal use, since most of my projects are under 10k lines and take a negligible amount of time to compile anyhow, I'd be in favor of this. However, for larger projects or projects that require things to work based only on interface, without access to the full source code, this is probably impractical.
Dec 18 2009
On Wed, 16 Dec 2009 19:05:09 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-16 16:46:14 -0500, Jason House <jason.james.house gmail.com> said:This can never work. a const?(Object) is const during the function execution, and cannot be assigned to.Walter Bright Wrote:Since this is just a special kind of const, it could be called "const^" (const or a derived constness): const?(Object) func(const?(Object) o) { return o; } The interesting thing about it, beside not taking a keyword, is that it can scale in the future if we need to add many distinct constness to the same function signature: const?(Object) func(const?(Object) o, const?2(Object) o2, out const?2(Object) o3) { o3 = o2; return o; }Jason House wrote:Of course, but it may still go through bikeshed issues. This morning I read about inout, return, vconst, aconst, sameconst, autoconst, auto const, and bikeshed. At least one of those was in jest :) auto const isn't that bad, and you obviously liked auto ref...KennyTM~ Wrote:The const transport thing is, unfortunately, a very different problem.auto const?I was wondering the same thing.Not that you'd need that often, but if it does becomes necessary in the future we'll still have some options. Furthermore, the concept could be extended to any type. This could be useful with class hierarchies: Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.This doesn't have the same utility as vconst, since you can't apply Object to other types like you can constancy. Plus you can already do this with a template and have a virtual version of the func: T func(T)(T o) if(T : Object) {func_virt(o); return o; } protected void func_virt(Object o) {writeln(o.toString());} -Steve
Dec 17 2009
On 2009-12-17 14:52:40 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:I'm not sure why, but I always forget that const(Object) is not rebindable. My mistake, here is the corrected example: const?(MyStruct)* func(const?(MyStruct)* s, const?2(MyStruct)* s2, const?2(MyStruct)* s3) { o2 = o3; return s; }The interesting thing about it, beside not taking a keyword, is that it can scale in the future if we need to add many distinct constness to the same function signature: const?(Object) func(const?(Object) o, const?2(Object) o2, out const?2(Object) o3) { o3 = o2; return o; }This can never work. a const?(Object) is const during the function execution, and cannot be assigned to.Indeed. I was mostly trying to show that the "const?" notation can easily be extended to all sort of things, which makes it a better choice than other notations. We could do the same with an old idea that didn't get in the language: scope arguments. // *a and *b are in the same scope, so you can swap a and b void swap(scope?(int)* a, scope?(int)* b) { int tmp = a; a = b; b = tmp; } But the scope problem would require more thought. -- Michel Fortin michel.fortin michelf.com http://michelf.com/Furthermore, the concept could be extended to any type. This could be useful with class hierarchies: Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.This doesn't have the same utility as vconst, since you can't apply Object to other types like you can constancy. Plus you can already do this with a template and have a virtual version of the func: T func(T)(T o) if(T : Object) {func_virt(o); return o; } protected void func_virt(Object o) {writeln(o.toString());}
Dec 17 2009
On Thu, 17 Dec 2009 15:17:22 -0500, Michel Fortin <michel.fortin michelf.com> wrote:On 2009-12-17 14:52:40 -0500, "Steven Schveighoffer" <schveiguy yahoo.com> said:That doesn't do anything :) It may as well be written: const?(MyStruct)* func(const?(MyStruct)* s) { return s; } If you want something like this: const?(MyStruct)* func(const?(MyStruct)* s, const?2(MyStruct)** s2, const?2(MyStruct)** s3) { *s2 = *s3; return s; } This will not accept any args except for const?(MyStruct)** for s2 and s3. That is, you cannot pass a MyStruct** or a const(MyStruct)** or an immutable(MyStruct)** because it is 2 levels of indirection (this is the test we ran earlier).I'm not sure why, but I always forget that const(Object) is not rebindable. My mistake, here is the corrected example: const?(MyStruct)* func(const?(MyStruct)* s, const?2(MyStruct)* s2, const?2(MyStruct)* s3) { o2 = o3; return s; }The interesting thing about it, beside not taking a keyword, is that it can scale in the future if we need to add many distinct constness to the same function signature: const?(Object) func(const?(Object) o, const?2(Object) o2, out const?2(Object) o3) { o3 = o2; return o; }This can never work. a const?(Object) is const during the function execution, and cannot be assigned to.OK, that makes more sense. Except scope is not a type constructor (yet) :) -SteveIndeed. I was mostly trying to show that the "const?" notation can easily be extended to all sort of things, which makes it a better choice than other notations. We could do the same with an old idea that didn't get in the language: scope arguments. // *a and *b are in the same scope, so you can swap a and b void swap(scope?(int)* a, scope?(int)* b) { int tmp = a; a = b; b = tmp; } But the scope problem would require more thought.Furthermore, the concept could be extended to any type. This could be useful with class hierarchies: Object? func(Object? o) { writeln(o.toString()); return o; } MyObject o = func(new MyObject); Here, "Object?" means Object or a derived type.This doesn't have the same utility as vconst, since you can't apply Object to other types like you can constancy. Plus you can already do this with a template and have a virtual version of the func: T func(T)(T o) if(T : Object) {func_virt(o); return o; } protected void func_virt(Object o) {writeln(o.toString());}
Dec 17 2009
On Wed, 16 Dec 2009 12:00:46 +0100, KennyTM~ <kennytm gmail.com> wrote:On Dec 16, 09 15:18, Walter Bright wrote:auto const auto ref Foo bar( auto const auto ref Foo arg ) { return arg; } Am I the only one who finds this confusing? -- SimenThere's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }auto const?
Dec 16 2009
Simen kjaeraas, el 17 de diciembre a las 02:16 me escribiste:On Wed, 16 Dec 2009 12:00:46 +0100, KennyTM~ <kennytm gmail.com> wrote:Just call "auto const auto ref" "auto auto": auto auto Foo bar( auto auto Foo arg ) { return arg; } =P -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- We are born naked, wet and hungry Then things get worseOn Dec 16, 09 15:18, Walter Bright wrote:auto const auto ref Foo bar( auto const auto ref Foo arg ) { return arg; } Am I the only one who finds this confusing?There's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }auto const?
Dec 17 2009
On Thu, 17 Dec 2009 17:26:52 +0100, Leandro Lucarella <llucax gmail.com> wrote:Simen kjaeraas, el 17 de diciembre a las 02:16 me escribiste:Even better, with return type inference: auto auto auto bar( T )( auto auto T arg ) { return arg; } :p -- SimenOn Wed, 16 Dec 2009 12:00:46 +0100, KennyTM~ <kennytm gmail.com> wrote:Just call "auto const auto ref" "auto auto": auto auto Foo bar( auto auto Foo arg ) { return arg; } =POn Dec 16, 09 15:18, Walter Bright wrote:auto const auto ref Foo bar( auto const auto ref Foo arg ) { return arg; } Am I the only one who finds this confusing?There's a need in generic code to have a function take a parameter by ref if it is an lvalue, and by value if it is an rvalue. This can be addressed by making it a template using auto ref: T foo(T)(auto ref T x) { ... } foo(3) // call by value int y; foo(y) // call by reference There is also a need to 'transmit' the ref'ness to the return value. This can be done with auto ref: auto ref foo(T)(auto ref T x) { return x; } foo(3) => int foo(int x) foo(y) => ref int foo(ref int x) This means that the generic forwarding function would look like: auto ref foo(alias F, T...)(auto ref T args) { return F(args); }auto const?
Dec 17 2009