Thread overview
byval keyword to make objects act as value types
Dec 23, 2007
BC
Dec 23, 2007
Christopher Wright
Dec 23, 2007
BC
Dec 23, 2007
BC
Dec 23, 2007
BC
Dec 23, 2007
Christopher Wright
Dec 23, 2007
Craig Black
Dec 23, 2007
BC
Dec 23, 2007
BC
Dec 23, 2007
Craig Black
December 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;

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 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.

then, we just need to return refs from functions, and it's goodbye C++!
December 23, 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 constructor

Perhaps 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 b

Besides 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++!
December 23, 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 *has* a dup method, or maybe a copy constructor
>
> Perhaps 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.
>
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 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.
>
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 *does* change the value of b
>
> Besides 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 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 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.
>
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.

>> then, we just need to return refs from functions, and it's goodbye C++!

December 23, 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 *has* a dup method, or maybe a copy constructor
>>
>> Perhaps 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.
>>
> 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 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.
>>
> 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 *does* change the value of b
>>
>> Besides which, arg isn't assigned to...
>>
>> void func(ref ValueClass arg) {
>>     arg = new ValueClass();
>> }
>>
i didn't realise you could have a reference to a reference

>>> 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 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 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.
>>
> no? currently the spec says you can't assign to them (although i see now
> that you can, if you like access violations), so i thought that might be
> 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++!
>

December 23, 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 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
>>>
>>> Perhaps 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.
>>>
>> 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 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.
>>>
>> 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 *does* change the value of b
>>>
>>> Besides which, arg isn't assigned to...
>>>
>>> void func(ref ValueClass arg) {
>>>     arg = new ValueClass();
>>> }
>>>
> i didn't realise you could have a reference to a reference
>
>>>> 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 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.
>>
arrghh. only in the vtbl if overriding a base class function, as they have
to be really. but not called virtually from references to the final class/
class in which they are final.

>>>> 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.
>>>
>> no? currently the spec says you can't assign to them (although i see now
>> that you can, if you like access violations), so i thought that might be
>> 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++!
>>
>

December 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 

December 23, 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 = 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

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.
December 23, 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 = 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
>
> 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.

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?
December 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 

December 23, 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.

>>> 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.
>>
> 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.

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.