www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Owned members

reply bearophile <bearophileHUGS lycos.com> writes:
I am far from being an expert C++ (or OOP) programmer still, so probably some
of my needs look (or are) naive.

This looks related to the old discussion of a 'scoped' attribute for class
members, but it's a different thing, more about the semantics of the code and
less about how the compiler implements things.

Sometimes I feel the need for something (usable on class/struct/enum members)
to tag a member as "owned" by the class instance. This attribute is useful only
for reference attributes, like objects, structs managed by pointer, associative
arrays and dynamic arrays. This attribute is purely a type system thing, the
compiled code doesn't change. It just disallows some kinds of code, shown
below. The purpose of  owned is to hopefully avoid some bugs.


class Foo {}

class Bar {
     owned private int[] array;
     owned private f Foo;
    
    public int[] giveArray() {
        return array; // error, a dup is required
    }
    public void receiveArray(int[] a) {
        array = a; // error, a dup is required
    }

    public Foo giveFoo() {
        return f; // error
    }
    public void receiveFoo(Foo ff) {
        f = ff; // error
    }
}


If array is owned by Bar, then "return array;" is a compile-time error because
the memory of the array is only owned by Bar; returning a slice or reference is
not allowed.

Is it possible to implement this  owned, and is it a good thing to have?

Bye,
bearophile
Dec 25 2010
parent reply spir <denis.spir gmail.com> writes:
On Sat, 25 Dec 2010 04:06:15 -0500
bearophile <bearophileHUGS lycos.com> wrote:

 I am far from being an expert C++ (or OOP) programmer still, so probably =
some of my needs look (or are) naive.
=20
 This looks related to the old discussion of a 'scoped' attribute for clas=
s members, but it's a different thing, more about the semantics of the code= and less about how the compiler implements things.
=20
 Sometimes I feel the need for something (usable on class/struct/enum memb=
ers) to tag a member as "owned" by the class instance. This attribute is us= eful only for reference attributes, like objects, structs managed by pointe= r, associative arrays and dynamic arrays. This attribute is purely a type s= ystem thing, the compiled code doesn't change. It just disallows some kinds= of code, shown below. The purpose of owned is to hopefully avoid some bug= s.
=20
=20
 class Foo {}
=20
 class Bar {
      owned private int[] array;
      owned private f Foo;
    =20
     public int[] giveArray() {
         return array; // error, a dup is required
     }
     public void receiveArray(int[] a) {
         array =3D a; // error, a dup is required
     }
=20
     public Foo giveFoo() {
         return f; // error
     }
     public void receiveFoo(Foo ff) {
         f =3D ff; // error
     }
 }
=20
=20
 If array is owned by Bar, then "return array;" is a compile-time error be=
cause the memory of the array is only owned by Bar; returning a slice or re= ference is not allowed.
=20
 Is it possible to implement this  owned, and is it a good thing to have?
I would enjoy to see a concrete, meaningful, example. It seems your point is to avoid sharing ref'ed elements --which is precisel= y the purpose of referencing, isn't it? What is the sense of having refere= nced elements if the references are not to be shared? On the other hand, refs may be useful from an implementation point of vue, = but not match the semantics. Then, you would need a tag like owned to give= back value semantics to referenced elements... Correct? What about the opposite (much rarer) case: An element that is typcally impl= emented as a value but conceptually is a referenced entity with identity. F= or instance, a plain string or even an int (here, actually a nominal) repre= senting a font (via its name or any kind of code). ? Googling should point you to 2-3 articles by Bertrand Meyer on the late int= roduction in Eiffel of a possibly related feature (don't remember how he ca= lled that). A typical case beeing the engine of a car: it is "owned" by, it= belongs, to the car. But it's still a proper entity with identity (and can= be shared, indeed, for instance a factory or car workshop may hold a ref t= o it.) AFAIK, neither of those concepts is commonly present in OO languages. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 25 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 I would enjoy to see a concrete, meaningful, example.
Often enough my class/struct members are arrays, and often I'd like the compiler to help me be more sure their memory is not shared (with a slice, for example) with something outside the instance. See below.
 It seems your point is to avoid sharing ref'ed elements --which is precisely
the purpose of referencing, isn't it?
That's one of the purposes of references, but there are other purposes. A dynamic array is allocated on the heap through a kind of fat reference so you are able to change its length. Objects in D are always managed by reference, so you have no choice.
 What is the sense of having referenced elements if the references are not to
be shared?
They are owned by the class instance :-) And even if you use emplace or scoped from Phobos, you still have a reference, so owned is useful even for scoped objects.
 Then, you would need a tag like  owned to give back value semantics to
referenced elements... Correct?
owned doesn't change the semantics and probably the resulting binary is unchanged. Its purpose is just to disable certain undesired (and buggy) behaviours, to keep class instance the only owner of the referenced object/array.
 What about the opposite (much rarer) case:
It's another thing.
 Googling should point you to 2-3 articles by Bertrand Meyer
I remember something by Meyer, but I don't remember if he was talking about instance ownership. I will read something again. Bye, bearophile
Dec 25 2010
parent reply "Alex Khmara" <alex.khmara gmail.com> writes:
On Sat, 25 Dec 2010 14:42:48 -0000, bearophile <bearophileHUGS lycos.com>  
wrote:

 spir:

 I would enjoy to see a concrete, meaningful, example.
Often enough my class/struct members are arrays, and often I'd like the compiler to help me be more sure their memory is not shared (with a slice, for example) with something outside the instance. See below.
 It seems your point is to avoid sharing ref'ed elements --which is  
 precisely the purpose of referencing, isn't it?
That's one of the purposes of references, but there are other purposes. A dynamic array is allocated on the heap through a kind of fat reference so you are able to change its length. Objects in D are always managed by reference, so you have no choice.
 What is the sense of having referenced elements if the references are  
 not to be shared?
They are owned by the class instance :-) And even if you use emplace or scoped from Phobos, you still have a reference, so owned is useful even for scoped objects.
 Then, you would need a tag like  owned to give back value semantics to  
 referenced elements... Correct?
owned doesn't change the semantics and probably the resulting binary is unchanged. Its purpose is just to disable certain undesired (and buggy) behaviours, to keep class instance the only owner of the referenced object/array.
 What about the opposite (much rarer) case:
It's another thing.
 Googling should point you to 2-3 articles by Bertrand Meyer
I remember something by Meyer, but I don't remember if he was talking about instance ownership. I will read something again. Bye, bearophile
I don' understand how this can be implemented in more complicated cases: class X { owned private int[] foo; int[] f1() { auto fooSlice = foo[0...3]; // is this valid? someExternalFunc(foo); // is this allowed? someExternalFunc(fooSlice) // how about this? return someFuncReturningArrayArg(fooSlice); // how to detect this? } } It seems that owned can work only in very primitive cases - otherwise complex escape analysis needed, and I even do not know if it will help. May be, if only pure function will be allowed to accept owned arguments, it will be ok, but power of this feature will be severely limited in this case.
Dec 25 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 25 Dec 2010 14:23:47 -0700, Alex Khmara <alex.khmara gmail.com>  
wrote:

 On Sat, 25 Dec 2010 14:42:48 -0000, bearophile  
 <bearophileHUGS lycos.com> wrote:

 spir:

 I would enjoy to see a concrete, meaningful, example.
Often enough my class/struct members are arrays, and often I'd like the compiler to help me be more sure their memory is not shared (with a slice, for example) with something outside the instance. See below.
 It seems your point is to avoid sharing ref'ed elements --which is  
 precisely the purpose of referencing, isn't it?
That's one of the purposes of references, but there are other purposes. A dynamic array is allocated on the heap through a kind of fat reference so you are able to change its length. Objects in D are always managed by reference, so you have no choice.
 What is the sense of having referenced elements if the references are  
 not to be shared?
They are owned by the class instance :-) And even if you use emplace or scoped from Phobos, you still have a reference, so owned is useful even for scoped objects.
 Then, you would need a tag like  owned to give back value semantics to  
 referenced elements... Correct?
owned doesn't change the semantics and probably the resulting binary is unchanged. Its purpose is just to disable certain undesired (and buggy) behaviours, to keep class instance the only owner of the referenced object/array.
 What about the opposite (much rarer) case:
It's another thing.
 Googling should point you to 2-3 articles by Bertrand Meyer
I remember something by Meyer, but I don't remember if he was talking about instance ownership. I will read something again. Bye, bearophile
I don' understand how this can be implemented in more complicated cases: class X { owned private int[] foo; int[] f1() { auto fooSlice = foo[0...3]; // is this valid? someExternalFunc(foo); // is this allowed? someExternalFunc(fooSlice) // how about this? return someFuncReturningArrayArg(fooSlice); // how to detect this? } } It seems that owned can work only in very primitive cases - otherwise complex escape analysis needed, and I even do not know if it will help. May be, if only pure function will be allowed to accept owned arguments, it will be ok, but power of this feature will be severely limited in this case.
This owned is very similar to previous 'scope' proposals (and oddly dissimilar to previous owned proposals). To answer your question, under previous proposals the scope keyword would allow you to declare that a variable doesn't escape the current scope. So you could define external functions that would take a 'scope int[]' and be guaranteed that it wouldn't escape. (returning scoped values has to obey certain restrictions) The previous 'owned' proposals are a bit more general. Owned types allow you parameterize a type on a variable, which sounds complex, but what it means in terms of the runtime, is that all objects in the same ownership group shared the same monitor. The big advantage is that inside a synchronized method you don't have to synchronize other 'owned' objects of the same type. It also makes this like unique a lot more viable, since you can now define trees, etc.
Dec 25 2010
parent reply "Alex Khmara" <alex.khmara gmail.com> writes:
On Sat, 25 Dec 2010 19:18:43 -0000, Robert Jacques <sandford jhu.edu>  
wrote:

 This  owned is very similar to previous 'scope' proposals (and oddly  
 dissimilar to previous owned proposals). To answer your question, under  
 previous proposals the scope keyword would allow you to declare that a  
 variable doesn't escape the current scope. So you could define external  
 functions that would take a 'scope int[]' and be guaranteed that it  
 wouldn't escape. (returning scoped values has to obey certain  
 restrictions)

 The previous 'owned' proposals are a bit more general. Owned types allow  
 you parameterize a type on a variable, which sounds complex, but what it  
 means in terms of the runtime, is that all objects in the same ownership  
 group shared the same monitor. The big advantage is that inside a  
 synchronized method you don't have to synchronize other 'owned' objects  
 of the same type. It also makes this like unique a lot more viable,  
 since you can now define trees, etc.
Ok, I'll try to find previous proposals about 'scope' - now I cannot understand how you can prevent external function from, e.g., saving owned object or array (i.e. references) in global variable, if it's at all possible to pass owned variables into external functions.
Dec 25 2010
parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 25 Dec 2010 15:18:07 -0700, Alex Khmara <alex.khmara gmail.com>  
wrote:

 On Sat, 25 Dec 2010 19:18:43 -0000, Robert Jacques <sandford jhu.edu>  
 wrote:

 This  owned is very similar to previous 'scope' proposals (and oddly  
 dissimilar to previous owned proposals). To answer your question, under  
 previous proposals the scope keyword would allow you to declare that a  
 variable doesn't escape the current scope. So you could define external  
 functions that would take a 'scope int[]' and be guaranteed that it  
 wouldn't escape. (returning scoped values has to obey certain  
 restrictions)

 The previous 'owned' proposals are a bit more general. Owned types  
 allow you parameterize a type on a variable, which sounds complex, but  
 what it means in terms of the runtime, is that all objects in the same  
 ownership group shared the same monitor. The big advantage is that  
 inside a synchronized method you don't have to synchronize other  
 'owned' objects of the same type. It also makes this like unique a lot  
 more viable, since you can now define trees, etc.
Ok, I'll try to find previous proposals about 'scope' - now I cannot understand how you can prevent external function from, e.g., saving owned object or array (i.e. references) in global variable, if it's at all possible to pass owned variables into external functions.
Well, think about pure. A pure function can call other pure functions, because those functions declare that they obey the rules of pure (i.e. no globals, etc). Scope variables can be passed to functions taking scoped parameters because those functions declare that they'll obey the rules of scope (i.e. they won't squirrel away references to it, etc).
Dec 25 2010
parent reply "Alex Khmara" <alex.khmara gmail.com> writes:
 Well, think about pure. A pure function can call other pure functions,  
 because those functions declare that they obey the rules of pure (i.e.  
 no globals, etc). Scope variables can be passed to functions taking  
 scoped parameters because those functions declare that they'll obey the  
 rules of scope (i.e. they won't squirrel away references to it, etc).
And so we have another complication in language - another transitive type modifier.
Dec 25 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Alex Khmara:

 And so we have another complication in language - another transitive type  
 modifier.
D and its programmers are able to sustain it :-) Bye, bearophile
Dec 25 2010
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Sat, 25 Dec 2010 16:38:19 -0700, Alex Khmara <alex.khmara gmail.com>  
wrote:

 Well, think about pure. A pure function can call other pure functions,  
 because those functions declare that they obey the rules of pure (i.e.  
 no globals, etc). Scope variables can be passed to functions taking  
 scoped parameters because those functions declare that they'll obey the  
 rules of scope (i.e. they won't squirrel away references to it, etc).
And so we have another complication in language - another transitive type modifier.
Well, it's only a proposal at this point. And things regarding scope/ownership have been fairly explicitly delayed to D3.
Dec 25 2010