digitalmars.D - byval keyword to make objects act as value types
- BC (29/29) Dec 22 2007 so that 'byval MyClass' is a new type that acts like MyClass in all ways...
- Christopher Wright (20/48) Dec 22 2007 Perhaps this would be better as a class declaration modifier?
- BC (19/63) Dec 22 2007 =
- BC (20/92) Dec 22 2007 =
- BC (20/109) Dec 22 2007 =
- Christopher Wright (7/21) Dec 23 2007 byval class VFoo {}
- Craig Black (5/13) Dec 22 2007 I'm not really "getting" your proposal, but maybe I missed something.
- BC (9/23) Dec 22 2007 =
- BC (12/36) Dec 23 2007 =
- Craig Black (19/23) Dec 23 2007 Good question. Here's my philosophy about virtual by default. I am a
so that 'byval MyClass' is a new type that acts like MyClass in all ways= = (ie. is polymorphic) except that it gets dupped on non-const assignment = = from other byval MyClasses and normal MyClasses. possibly also on = assignment to normal MyClasses. this would require that it *has* a dup = method, or maybe a copy constructor byval Base b =3D new Derived; despite the name 'byval' b actually holds a reference to a copy of = Derived, so slicing is avoided. or, if that's too inefficient perhaps the linker can figure out the size= = of the largest class derived from Base and allocate that much on the = stack/inside a containing class. myFunction(ref Base arg) { ++arg; } myFunction(b) i'm thinking it should be overridable so that the above function *does* = = change the value of b question: are calls to final class member functions non-virtual? i notice the tango iterators are classes. surely we want to use iterator= s = as value types... this way, we can. alternatively, since scope objects are a bit like value types already, = perhaps we can just add the functionality to that. then, we just need to return refs from functions, and it's goodbye C++!
Dec 22 2007
BC wrote:so that 'byval MyClass' is a new type that acts like MyClass in all ways (ie. is polymorphic) except that it gets dupped on non-const assignment from other byval MyClasses and normal MyClasses. possibly also on assignment to normal MyClasses. this would require that it *has* a dup method, or maybe a copy constructorPerhaps this would be better as a class declaration modifier? byval class Foo {} // acts like a struct Or: valueclass Foo {} It would be simpler, at least: an opAssign overload.byval Base b = new Derived; despite the name 'byval' b actually holds a reference to a copy of Derived, so slicing is avoided. or, if that's too inefficient perhaps the linker can figure out the size of the largest class derived from Base and allocate that much on the stack/inside a containing class.If we get this, I'm going to ask for virtual template methods in classes again. It's not happening.myFunction(ref Base arg) { ++arg; } myFunction(b) i'm thinking it should be overridable so that the above function *does* change the value of bBesides which, arg isn't assigned to... void func(ref ValueClass arg) { arg = new ValueClass(); }question: are calls to final class member functions non-virtual?Well, yes. But do you mean, are they found in the vtbl? You could check: class Foo { final void a(){} final void b(){} final void c(){} } assert (Foo.classinfo.vtbl.length == Object.classinfo.vtbl.length);i notice the tango iterators are classes. surely we want to use iterators as value types... this way, we can. alternatively, since scope objects are a bit like value types already, perhaps we can just add the functionality to that.Ugh. No.then, we just need to return refs from functions, and it's goodbye C++!
Dec 22 2007
On Sun, 23 Dec 2007 04:01:30 -0000, Christopher Wright = <dhasenan gmail.com> wrote:BC wrote:so that 'byval MyClass' is a new type that acts like MyClass in all =ways (ie. is polymorphic) except that it gets dupped on non-const ==assignment from other byval MyClasses and normal MyClasses. possibly =also on assignment to normal MyClasses. this would require that it =true, it's just that I don't buy that classes are always either value or= reference types, I think flexibility is desirable. you could still do class Foo{} alias byval Foo VFoo;*has* a dup method, or maybe a copy constructorPerhaps this would be better as a class declaration modifier? byval class Foo {} // acts like a struct Or: valueclass Foo {} It would be simpler, at least: an opAssign overload.byval Base b =3D new Derived; despite the name 'byval' b actually holds a reference to a copy of =Derived, so slicing is avoided. or, if that's too inefficient perhaps the linker can figure out the ==size of the largest class derived from Base and allocate that much on=es =the stack/inside a containing class.If we get this, I'm going to ask for virtual template methods in class=again. It's not happening.no, i'm not holding my breath. it could for final classes though.myFunction(ref Base arg) { ++arg; } myFunction(b) i'm thinking it should be overridable so that the above function =k:*does* change the value of bBesides which, arg isn't assigned to... void func(ref ValueClass arg) { arg =3D new ValueClass(); }question: are calls to final class member functions non-virtual?Well, yes. But do you mean, are they found in the vtbl? You could chec=class Foo { final void a(){} final void b(){} final void c(){} } assert (Foo.classinfo.vtbl.length =3D=3D Object.classinfo.vtbl.length)=;i should have said 'member functions of final classes'. both are found in the vtbl. i was wondering how close to struct behaviour we can bring classes.i notice the tango iterators are classes. surely we want to use =y, =iterators as value types... this way, we can. alternatively, since scope objects are a bit like value types alread=no? currently the spec says you can't assign to them (although i see now= that you can), so i thought that might be the plan.perhaps we can just add the functionality to that.Ugh. No.+!then, we just need to return refs from functions, and it's goodbye C+=
Dec 22 2007
On Sun, 23 Dec 2007 05:09:43 -0000, BC = <NOTmi_emayl_adrez hotmail.com.remove.not> wrote:On Sun, 23 Dec 2007 04:01:30 -0000, Christopher Wright =<dhasenan gmail.com> wrote:=BC wrote:so that 'byval MyClass' is a new type that acts like MyClass in all =ways (ie. is polymorphic) except that it gets dupped on non-const ==assignment from other byval MyClasses and normal MyClasses. possibly=also on assignment to normal MyClasses. this would require that it =ortrue, it's just that I don't buy that classes are always either value =*has* a dup method, or maybe a copy constructorPerhaps this would be better as a class declaration modifier? byval class Foo {} // acts like a struct Or: valueclass Foo {} It would be simpler, at least: an opAssign overload.reference types, I think flexibility is desirable. you could still do class Foo{} alias byval Foo VFoo;=byval Base b =3D new Derived; despite the name 'byval' b actually holds a reference to a copy of ==Derived, so slicing is avoided. or, if that's too inefficient perhaps the linker can figure out the =n =size of the largest class derived from Base and allocate that much o=the stack/inside a containing class.If we get this, I'm going to ask for virtual template methods in =classes again. It's not happening.no, i'm not holding my breath. it could for final classes though.myFunction(ref Base arg) { ++arg; } myFunction(b) i'm thinking it should be overridable so that the above function =i didn't realise you could have a reference to a reference*does* change the value of bBesides which, arg isn't assigned to... void func(ref ValueClass arg) { arg =3D new ValueClass(); }ck:question: are calls to final class member functions non-virtual?Well, yes. But do you mean, are they found in the vtbl? You could che=);class Foo { final void a(){} final void b(){} final void c(){} } assert (Foo.classinfo.vtbl.length =3D=3D Object.classinfo.vtbl.length=i should have said 'member functions of final classes'. both are found=in the vtbl. i was wondering how close to struct behaviour we can brin=gclasses.i notice the tango iterators are classes. surely we want to use =iterators as value types... this way, we can. alternatively, since scope objects are a bit like value types =owno? currently the spec says you can't assign to them (although i see n=already, perhaps we can just add the functionality to that.Ugh. No.that you can, if you like access violations), so i thought that might =bethe plan.don't forget that if you assign it to something else such as a scope obj= ect inside another class, you get a copy, which won't get destroyed, so they could then outlast the function scope and be just like a value type as far as i can see.++!then, we just need to return refs from functions, and it's goodbye C=
Dec 22 2007
On Sun, 23 Dec 2007 05:40:34 -0000, BC = <NOTmi_emayl_adrez hotmail.com.remove.not> wrote:On Sun, 23 Dec 2007 05:09:43 -0000, BC =<NOTmi_emayl_adrez hotmail.com.remove.not> wrote:On Sun, 23 Dec 2007 04:01:30 -0000, Christopher Wright ==<dhasenan gmail.com> wrote:BC wrote:so that 'byval MyClass' is a new type that acts like MyClass in all=ways (ie. is polymorphic) except that it gets dupped on non-const =y =assignment from other byval MyClasses and normal MyClasses. possibl==also on assignment to normal MyClasses. this would require that it =ortrue, it's just that I don't buy that classes are always either value=*has* a dup method, or maybe a copy constructorPerhaps this would be better as a class declaration modifier? byval class Foo {} // acts like a struct Or: valueclass Foo {} It would be simpler, at least: an opAssign overload.reference types, I think flexibility is desirable. you could still do==class Foo{} alias byval Foo VFoo;byval Base b =3D new Derived; despite the name 'byval' b actually holds a reference to a copy of==Derived, so slicing is avoided. or, if that's too inefficient perhaps the linker can figure out the=on =size of the largest class derived from Base and allocate that much =the stack/inside a containing class.If we get this, I'm going to ask for virtual template methods in =classes again. It's not happening.no, i'm not holding my breath. it could for final classes though.myFunction(ref Base arg) { ++arg; } myFunction(b) i'm thinking it should be overridable so that the above function =i didn't realise you could have a reference to a reference*does* change the value of bBesides which, arg isn't assigned to... void func(ref ValueClass arg) { arg =3D new ValueClass(); }question: are calls to final class member functions non-virtual?Well, yes. But do you mean, are they found in the vtbl? You could =h);check: class Foo { final void a(){} final void b(){} final void c(){} } assert (Foo.classinfo.vtbl.length =3D=3D Object.classinfo.vtbl.lengt=di should have said 'member functions of final classes'. both are foun=ngin the vtbl. i was wondering how close to struct behaviour we can bri=arrghh. only in the vtbl if overriding a base class function, as they ha= ve to be really. but not called virtually from references to the final clas= s/ class in which they are final.classes.i notice the tango iterators are classes. surely we want to use =iterators as value types... this way, we can. alternatively, since scope objects are a bit like value types =nowno? currently the spec says you can't assign to them (although i see =already, perhaps we can just add the functionality to that.Ugh. No.bethat you can, if you like access violations), so i thought that might=the plan.don't forget that if you assign it to something else such as a scope =object inside another class, you get a copy, which won't get destroyed, so they could then outlast the function scope and be just like a value=type as far as i can see.=then, we just need to return refs from functions, and it's goodbye =C++!
Dec 22 2007
BC wrote:true, it's just that I don't buy that classes are always either value or reference types, I think flexibility is desirable. you could still do class Foo{} alias byval Foo VFoo;byval class VFoo {} alias VFoo* Foo; Close enough.Unless you can get the functionality while maintaining the current behavior of the scope storage class, I'm against it. You'd never get an unambiguous rule to determine which is to be used in the current case.no? currently the spec says you can't assign to them (although i see now that you can), so i thought that might be the plan.i notice the tango iterators are classes. surely we want to use iterators as value types... this way, we can. alternatively, since scope objects are a bit like value types already, perhaps we can just add the functionality to that.Ugh. No.
Dec 23 2007
so that 'byval MyClass' is a new type that acts like MyClass in all ways (ie. is polymorphic) except that it gets dupped on non-const assignment from other byval MyClasses and normal MyClasses. possibly also on assignment to normal MyClasses. this would require that it *has* a dup method, or maybe a copy constructor byval Base b = new Derived;I'm not really "getting" your proposal, but maybe I missed something. What's the novelty here? Why not just add copy semantics to structs? Then you don't need the byval keyword anymore.i notice the tango iterators are classes. surely we want to use iterators as value types... this way, we can.I wholeheartedly agree, but why not use structs? -Craig
Dec 22 2007
On Sun, 23 Dec 2007 06:22:49 -0000, Craig Black <craigblack2 cox.net> = wrote:so that 'byval MyClass' is a new type that acts like MyClass in all =ways (ie. is polymorphic) except that it gets dupped on non-const ==assignment from other byval MyClasses and normal MyClasses. possibly =also on assignment to normal MyClasses. this would require that it ==*has* a dup method, or maybe a copy constructor byval Base b =3D new Derived;I'm not really "getting" your proposal, but maybe I missed something. =What's the novelty here? Why not just add copy semantics to structs? ==Then you don't need the byval keyword anymore.i notice the tango iterators are classes. surely we want to use =well, there's inheritance. polymorphism. also there's not always a = definitive answer to whether a given data structure should be a value or reference type. this way, they can be both.iterators as value types... this way, we can.I wholeheartedly agree, but why not use structs? -Craig
Dec 22 2007
On Sun, 23 Dec 2007 07:52:06 -0000, BC = <notmi_emayl_adreznot hotmail.com.remove.not> wrote:On Sun, 23 Dec 2007 06:22:49 -0000, Craig Black <craigblack2 cox.net> ==wrote:=so that 'byval MyClass' is a new type that acts like MyClass in all =ways (ie. is polymorphic) except that it gets dupped on non-const ==assignment from other byval MyClasses and normal MyClasses. possibly=also on assignment to normal MyClasses. this would require that it ==*has* a dup method, or maybe a copy constructor byval Base b =3D new Derived;I'm not really "getting" your proposal, but maybe I missed something.==What's the novelty here? Why not just add copy semantics to structs?=Then you don't need the byval keyword anymore.i notice the tango iterators are classes. surely we want to use =well, there's inheritance. polymorphism. also there's not always a =iterators as value types... this way, we can.I wholeheartedly agree, but why not use structs? -Craigdefinitive answer to whether a given data structure should be a value or referenc=etype. this way, they can be both.although adding those things and ctors/dtors to structs like you said would be just as good really. i got the impression that option was off the table though. should struct member functions & dtors be virtual by default?
Dec 23 2007
although adding those things and ctors/dtors to structs like you said would be just as good really. i got the impression that option was off the table though. should struct member functions & dtors be virtual by default?Good question. Here's my philosophy about virtual by default. I am a performance-oriented guy, and I prefer the compiler to NOT make functions virtual when I don't explicitly say "virtual". For me, virtual by default means I need to be more careful about overriding so something doesn't become virtual accidentally. Further, virtual by default prevents non-virtual overriding, which can be used for high-performance compile-time polymorphism using templates. That said, if this happens at all, Walter would probably use virtual by default for consistency sake. Oh well, I guess it's not that big a deal. If polymorphism is added to structs, it should be optional. I would have a problem if the vtable pointer was included in structs that didn't have any polymorphism. It should work like C++ structs and classes, where there is no overhead for non-polymorphic types. As for virtual destructors, I agree that they should be virtual by default, but only if a type is polymorphic. Forgetting to make a destructor virtual in C++ can cause subtle and annoying bugs. It's good that most C++ compilers issue warnings when a polymorphic type has a non-virtual destructor. However, I would rather the compiler make it virtual for me. -Craig
Dec 23 2007