www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why there are no 'physical' object variables (only references)?

reply Kristian <kjkilpi gmail.com> writes:
I'm used for having both the variable types, 'physical' and  =

reference(/pointer) ones, so it feels strange to work with D (or Java,  =

etc) that have reference types only.

First, there is no way to copy/clone an object (in general). That is,  =

unless you provide a copy/clone function (for all the classes you're  =

using). Second, you cannot create classes that behave like basic types, =
 =

e.g. like integers.

For example, in C++ you could have:

void func() {
     Coord a, b, c;

     a.set(1, 2);
     b.set(5, 10);
     c =3D a + b;  //'c' is (6, 12)
     b =3D c;
     b.setX(2);  //'c' is unchanged, 'b' is (2, 12)
}

The 'Coord' objects have no 'global meaning' here, they are just simple =
 =

values used in calculations. (So there is no need to reference them from=
  =

other parts of the code.)

I think it's a big restriction if a language does not have both the  =

variable types (physical + references).
Why D and other similar languages have no physical types?


And, I hope that D will have a 'const' type specifier in the future. Now=
  =

you cannot know if a function will modify an object that is passed to it=
  =

as a parameter. Or if a member function of a class will change the  =

internal status of the object.

When these things are summed together, I'm afraid that I (at least) will=
  =

create a number of situations where the values of objects are incorrectl=
y  =

changed in almost any part of the code. Hopefully not, though.
Sep 10 2006
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Kristian wrote:
 I'm used for having both the variable types, 'physical' and 
 reference(/pointer) ones, so it feels strange to work with D (or Java, 
 etc) that have reference types only.
 
 First, there is no way to copy/clone an object (in general). That is, 
 unless you provide a copy/clone function (for all the classes you're 
 using). Second, you cannot create classes that behave like basic types, 
 e.g. like integers.
 
 For example, in C++ you could have:
 
 void func() {
     Coord a, b, c;
 
     a.set(1, 2);
     b.set(5, 10);
     c = a + b;  //'c' is (6, 12)
     b = c;
     b.setX(2);  //'c' is unchanged, 'b' is (2, 12)
 }
 
 The 'Coord' objects have no 'global meaning' here, they are just simple 
 values used in calculations. (So there is no need to reference them from 
 other parts of the code.)
 
 I think it's a big restriction if a language does not have both the 
 variable types (physical + references).
 Why D and other similar languages have no physical types?
I think D structs are the "physical" variable type you're looking for. They allow everything above. The Coord type + minor modifications to your code for testing: struct Coord { int x,y; void set(int x_, int y_) { x = x_; y = y_; } void setX(int x_) { x = x_; } Coord opAdd(Coord c) { Coord ret; ret.x = x + c.x; ret.y = y + c.y; return ret; } } void main() { Coord a, b, c; a.set(1, 2); b.set(5, 10); c = a + b; //'c' is (6, 12) b = c; b.setX(2); //'c' is unchanged, 'b' is (2, 12) // Check everything worked as planned: assert(a.x == 1); assert(a.y == 2); assert(b.x == 2); assert(b.y == 12); assert(c.x == 6); assert(c.y == 12); } Runs without any asserts triggering. Of course that's just a minimal working type, not how one would typically write such a type. For one thing, either make x and y private and add setY, getX and getY or get rid of set and setX. For another, you'll probably want some more operators (equality, subtraction, maybe "multiply by scalar"). Not everything needs to be a class. I see no reason why a type like Coord would need inheritance.
 And, I hope that D will have a 'const' type specifier in the future. Now 
 you cannot know if a function will modify an object that is passed to it 
 as a parameter. Or if a member function of a class will change the 
 internal status of the object.
Yes, "const reference" parameters are something D doesn't do, unfortunately.
 When these things are summed together, I'm afraid that I (at least) will 
 create a number of situations where the values of objects are 
 incorrectly changed in almost any part of the code. Hopefully not, though.
Sep 10 2006
parent reply Kristian <kjkilpi gmail.com> writes:
On Sun, 10 Sep 2006 16:09:23 +0300, Frits van Bommel  
<fvbommel REMwOVExCAPSs.nl> wrote:
[snip]
  The 'Coord' objects have no 'global meaning' here, they are just  
 simple values used in calculations. (So there is no need to reference  
 them from other parts of the code.)
  I think it's a big restriction if a language does not have both the  
 variable types (physical + references).
 Why D and other similar languages have no physical types?
I think D structs are the "physical" variable type you're looking for. They allow everything above.
[snip] Ah, of course, basic types can be usually implemented as structures, thanks. :) Unfortunately some of the types have to be implemented as classes (e.g. a file class) because of the inheritance and/or constructors/destructors. Hmm, what if structures could have interfaces and constructors/destructors... and what the heck, inheritance too? Hehheh, this way we would have 'physical classes' for local use and 'reference classes' for global use. Or we could have a new data type instead: type Coord {...} //like a class except its objects do not use referencing That would be weird... or would it?
Sep 10 2006
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Kristian wrote:
 
 Hmm, what if structures could have interfaces and 
 constructors/destructors... and what the heck, inheritance too? Hehheh, 
 this way we would have 'physical classes' for local use and 'reference 
 classes' for global use.
It will never happen :-) Though ctor support would be nice, at the very least. That would simplify initialization and eliminate the need for the static opCall trick. Sean
Sep 10 2006
parent reply BCS <BCS pathlink.com> writes:
Sean Kelly wrote:
 Kristian wrote:
 
 Hmm, what if structures could have interfaces and 
 constructors/destructors... and what the heck, inheritance too? 
 Hehheh, this way we would have 'physical classes' for local use and 
 'reference classes' for global use.
It will never happen :-) Though ctor support would be nice, at the very least. That would simplify initialization and eliminate the need for the static opCall trick. Sean
There is no technical reason struct (or anything that can produce a delegate) can't do interfaces. Inheritance on the other hand... I hope that never happens.
Sep 11 2006
parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
BCS wrote:
 Sean Kelly wrote:
 Kristian wrote:

 Hmm, what if structures could have interfaces and 
 constructors/destructors... and what the heck, inheritance too? 
 Hehheh, this way we would have 'physical classes' for local use and 
 'reference classes' for global use.
It will never happen :-) Though ctor support would be nice, at the very least. That would simplify initialization and eliminate the need for the static opCall trick. Sean
There is no technical reason struct (or anything that can produce a delegate) can't do interfaces. Inheritance on the other hand... I hope that never happens.
Wouldn't it add a hidden __vtbl to your struct and thereby increasing its size? L.
Sep 11 2006
parent reply BCS <BCS pathlink.com> writes:
Lionello Lunesu wrote:
 BCS wrote:
 
 Sean Kelly wrote:

 Kristian wrote:

 Hmm, what if structures could have interfaces and 
 constructors/destructors... and what the heck, inheritance too? 
 Hehheh, this way we would have 'physical classes' for local use and 
 'reference classes' for global use.
It will never happen :-) Though ctor support would be nice, at the very least. That would simplify initialization and eliminate the need for the static opCall trick. Sean
There is no technical reason struct (or anything that can produce a delegate) can't do interfaces. Inheritance on the other hand... I hope that never happens.
Wouldn't it add a hidden __vtbl to your struct and thereby increasing its size? L.
No, because the type of a struct is always known, the required value for the interface's function table can be found at compile time and all that is needed is to attach it to a reference to the struct.
Sep 12 2006
parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
BCS wrote:
 Lionello Lunesu wrote:
 BCS wrote:

 Sean Kelly wrote:

 Kristian wrote:

 Hmm, what if structures could have interfaces and 
 constructors/destructors... and what the heck, inheritance too? 
 Hehheh, this way we would have 'physical classes' for local use and 
 'reference classes' for global use.
It will never happen :-) Though ctor support would be nice, at the very least. That would simplify initialization and eliminate the need for the static opCall trick. Sean
There is no technical reason struct (or anything that can produce a delegate) can't do interfaces. Inheritance on the other hand... I hope that never happens.
Wouldn't it add a hidden __vtbl to your struct and thereby increasing its size? L.
No, because the type of a struct is always known, the required value for the interface's function table can be found at compile time and all that is needed is to attach it to a reference to the struct.
I don't understand you. How would it work? Suppose you had this code: interface Foo { int foo(); } struct Bar : Foo { int foo() { ... } ... } void calc(Foo f) { ... } How can calc know the type of every struct it is passed unless a separate version of calc is generated for every type (in which case it is just a template)? Cheers, Reiner
Sep 12 2006
next sibling parent reply Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Wed, 13 Sep 2006 06:33:19 +1000, Reiner Pope
<reiner.pope REMOVE.THIS.gmail.com> wrote:

interface Foo
<SNIP>
struct Bar : Foo
<SNIP>
void calc(Foo f) { ... }

How can calc know the type of every struct it is passed unless a 
separate version of calc is generated for every type (in which case it 
is just a template)?
Compiler generated proxy object, containing a vtable and a pointer to the struct. To pass the struct as an interface, you need some kind of reference anyway. You can't just pass the whole struct. A reference to a proxy object would make at least some sense. Mind you, it's very dodgy, to say the least. I have argued for struct inheritance, but this is not the kind of inheritance I want. I still want structs to be data, not reference-free objects. -- Remove 'wants' and 'nospam' from e-mail.
Sep 13 2006
parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Steve Horne wrote:
 On Wed, 13 Sep 2006 06:33:19 +1000, Reiner Pope
 <reiner.pope REMOVE.THIS.gmail.com> wrote:
 
 interface Foo
<SNIP>
 struct Bar : Foo
<SNIP>
 void calc(Foo f) { ... }

 How can calc know the type of every struct it is passed unless a 
 separate version of calc is generated for every type (in which case it 
 is just a template)?
Compiler generated proxy object, containing a vtable and a pointer to the struct.
What's the difference between this and a class, then?
 Mind you, it's very dodgy, to say the least. I have argued for struct
 inheritance, but this is not the kind of inheritance I want.
I don't understand what you do want, then. Interface inheritance requires class-like vtables, and once you've got that you've basically got a class, anyway. *Implementation* inheritance can be done using mixins. Of course, in D, implementation inheritance via mixins is a bit limited -- you can only mix in templates, not structs. I see no technical reason why you couldn't mix in any class, function, or struct that you have the source code for. This basically means implicitly templatizing whatever you want to mix in. Cheers, Reiner
Sep 13 2006
parent Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Wed, 13 Sep 2006 19:09:20 +1000, Reiner Pope
<reiner.pope REMOVE.THIS.gmail.com> wrote:

 Compiler generated proxy object, containing a vtable and a pointer to
 the struct.
What's the difference between this and a class, then?
Er - you'd have to write the class yourself?
 Mind you, it's very dodgy, to say the least. I have argued for struct
 inheritance, but this is not the kind of inheritance I want.
I don't understand what you do want, then. Interface inheritance
I never said I want interface support for structs. I just joined in a thread on someone elses idea. Just saying its possible - not that it's a good idea ;-) The struct inheritance I want allows structs to inherit from structs, adding a few extra data fields. What to do about methods, I don't know. I'm not comfortable with structs having methods anyway - a result of a style developed in C++ where the keywords 'struct' and 'class' tend to imply different things to programmers even though the compiler sees them the same. And I'm not all that fussed about struct inheritance either. Just can't leave things alone when people disagree with me ;-) -- Remove 'wants' and 'nospam' from e-mail.
Sep 13 2006
prev sibling parent BCS <BCS pathlink.com> writes:
Reiner Pope wrote:
 BCS wrote:
 
[...]
 No, because the type of a struct is always known, the required value 
 for the interface's function table can be found at compile time and 
 all that is needed is to attach it to a reference to the struct.
I don't understand you. How would it work? Suppose you had this code: interface Foo { int foo(); } struct Bar : Foo { int foo() { ... } ... }
If I understand it correctly interfaces variables are a fat pointer, sort of like a delegate. They could be implemented something like this: struct Interface { void* context; void*[] v_table; } When a class implements an interface it creates a static array containing pointers to it's methods. A reference to this array is placed in that classes v-table. When an interface instance is needed something like this is done: class C : Foo {...} C c = new C; Interface i; // set context i.context = c; // set v-table i.v_table = c.vtbl[C.Foo_index]; When an interface is used to call a method it ends up looking something like this (omitting a bunch of casts): i.v_table[Foo.foo_index](i.context); The only reason that the v-table for the interface is referenced by way of the v-table of the class is that the actual type of the class isn't known until run time. For a struct, that isn't the case, the type is always known. Their for, something like this can be done. Bar bar; // set context i.context = &bar; // set v-table i.v_table = Bar.Foo_vtbl]; this doesn't require any v-table in Foo
 void calc(Foo f) { ... }

 How can calc know the type of every struct it is passed unless a
 separate version of calc is generated for every type (in which case it
 is just a template)?
a function that uses an interface NEVER knowns the type of the underlying data. In fact the only way it ever uses it is by passing it as a context to one of the function accessed by way of the v-table referenced in the /interface/ this is analogous to a function taking a delegate not caring what the context of that delegate is.
 Cheers,

 Reiner
Sep 13 2006
prev sibling parent Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Sun, 10 Sep 2006 17:55:54 +0300, Kristian <kjkilpi gmail.com>
wrote:

Hmm, what if structures could have interfaces and  
constructors/destructors... and what the heck, inheritance too?
I've promissed myself that I'm not going to say anything else about struct inheritance, so I'm keeping quiet ;-) -- Remove 'wants' and 'nospam' from e-mail.
Sep 10 2006
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Kristian wrote:
 I'm used for having both the variable types, 'physical' and 
 reference(/pointer) ones, so it feels strange to work with D (or Java, 
 etc) that have reference types only.
 
 First, there is no way to copy/clone an object (in general). That is, 
 unless you provide a copy/clone function (for all the classes you're 
 using).
Yup. The .dup property is pretty standard, but there's no convention for whether this should represent deep or shallow copy (though shallow seems to make more sense).
 Second, you cannot create classes that behave like basic types,
 e.g. like integers.
True. You can get pretty close, but D does not support an assignment operator and there is no universal construction syntax as there is in C++. This was a deliberate decision, as handling copyable objects in C++ is a common source of bugs.
 For example, in C++ you could have:
 
 void func() {
     Coord a, b, c;
 
     a.set(1, 2);
     b.set(5, 10);
     c = a + b;  //'c' is (6, 12)
     b = c;
     b.setX(2);  //'c' is unchanged, 'b' is (2, 12)
 }
 
 The 'Coord' objects have no 'global meaning' here, they are just simple 
 values used in calculations. (So there is no need to reference them from 
 other parts of the code.)
 
 I think it's a big restriction if a language does not have both the 
 variable types (physical + references).
 Why D and other similar languages have no physical types?
Currently, you can use a struct or construct a class in place using alloca. Eventually, we will get a stack allocation syntax for classes along the lines of: Coord a = Coord(); // note there is no 'new' I also proposed an '.isizeof' property to return the instance size of a reference/pointer at compile-time, but there was little interest in the idea. However, it would allow you to do things like this: byte[Coord.isizeof] buf; // assume buf is properly aligned Coord a = new(&buf[0]) Coord();
 And, I hope that D will have a 'const' type specifier in the future. Now 
 you cannot know if a function will modify an object that is passed to it 
 as a parameter. Or if a member function of a class will change the 
 internal status of the object.
Don't we all. But wanting it and coming up with a solid proposal for how it should work are entirely different issues, unfortunately. Sean
Sep 10 2006
parent reply Kristian <kjkilpi gmail.com> writes:
On Sun, 10 Sep 2006 18:59:34 +0300, Sean Kelly <sean f4.ca> wrote:
 Kristian wrote:
  First, there is no way to copy/clone an object (in general). That is=
, =
 unless you provide a copy/clone function (for all the classes you're =
=
 using).
Yup. The .dup property is pretty standard, but there's no convention =
=
 for whether this should represent deep or shallow copy (though shallow=
=
 seems to make more sense).
Maybe there should be two properties, .dup and .deepdup (or something, a name .ddup is probably too similar).
 True.  You can get pretty close, but D does not support an assignment
 operator and there is no universal construction syntax as there is in =
=
 C++.
 This was a deliberate decision, as handling copyable objects
 in C++ is a common source of bugs.
Really? I mean, a common source of bugs? But isn't it be simple to fix = such bugs, just correct the copy methods? With references there may be = bugs much harder to find: an object you're referencing is changed = somewhere you don't know. You may have to trace a lot of code to find = where the object gets modified, and correct things around the code, not = = just in one class. And what if you need copy/clone methods? You implement them by yourself = = (if there is no .deepdub). Using them is not so 'nice' because you can't= = override the assignment operator, etc. These copyable objects are still = 'a = source of bugs', even if used via references, of course. (And I have to also mention :) that nobody forces you to use copy method= s = in C++. You can use objects via pointers only. But why people don't? = Because copyable objects suit better in some situations.)
 Currently, you can use a struct or construct a class in place using  =
 alloca.  Eventually, we will get a stack allocation syntax for classes=
=
 along the lines of:

      Coord a =3D Coord(); // note there is no 'new'
Or maybe using a syntax (I have mentioned earlier): Coord a();
 And, I hope that D will have a 'const' type specifier in the future. =
=
 Now you cannot know if a function will modify an object that is passe=
d =
 to it as a parameter. Or if a member function of a class will change =
=
 the internal status of the object.
Don't we all. But wanting it and coming up with a solid proposal for =
=
 how it should work are entirely different issues, unfortunately.
Well, what's wrong with the way C++ does it? class Obj { void f() const; void g(); int v; } void func(const Obj o) { o.f(); //ok o.g(); //error o.v =3D 1; //error }
Sep 10 2006
next sibling parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Kristian wrote:
 On Sun, 10 Sep 2006 18:59:34 +0300, Sean Kelly <sean f4.ca> wrote:
 Kristian wrote:
 And, I hope that D will have a 'const' type specifier in the future. 
 Now you cannot know if a function will modify an object that is 
 passed to it as a parameter. Or if a member function of a class will 
 change the internal status of the object.
Don't we all. But wanting it and coming up with a solid proposal for how it should work are entirely different issues, unfortunately.
Well, what's wrong with the way C++ does it? class Obj { void f() const; void g(); int v; } void func(const Obj o) { o.f(); //ok o.g(); //error o.v = 1; //error }
Do some searching for 'const' and 'readonly' on this NG, and you should get the idea: - C++ const is ugly, so people don't use it enough; - const_cast removes the safety guarantees of const, making const-directed optimizations by the compiler impossible. - overloading by const requires duplication of code. - a trivial const system like C++ is too strict and may require unnecessary clones to avoid a static const violation, thus necessitating the need for const_cast - reference immutability (C++'s 'readonly view') is only one form of const, and can't guarantee other (important) immutability contracts - after such a problems, the merits are not so clear, since the usefulness can only really be attributed to two things: 1. Standardising documentation of variable usage. 2. Getting the compiler to help catch programmer errors. and some people claim that they have never found any bugs by using const. Cheers, Reiner
Sep 10 2006
parent reply Kristian <kjkilpi gmail.com> writes:
On Sun, 10 Sep 2006 23:48:22 +0300, Reiner Pope  
<reiner.pope REMOVE.THIS.gmail.com> wrote:

 Kristian wrote:
 On Sun, 10 Sep 2006 18:59:34 +0300, Sean Kelly <sean f4.ca> wrote:
 Kristian wrote:
 And, I hope that D will have a 'const' type specifier in the future.
[snip]
 Don't we all.  But wanting it and coming up with a solid proposal for  
 how it should work are entirely different issues, unfortunately.
Well, what's wrong with the way C++ does it?
[snip]
 Do some searching for 'const' and 'readonly' on this NG, and you should  
 get the idea:
   - C++ const is ugly, so people don't use it enough;
   - const_cast removes the safety guarantees of const, making  
 const-directed optimizations by the compiler impossible.
   - overloading by const requires duplication of code.
   - a trivial const system like C++ is too strict and may require  
 unnecessary clones to avoid a static const violation, thus necessitating  
 the need for const_cast
   - reference immutability (C++'s 'readonly view') is only one form of  
 const, and can't guarantee other (important) immutability contracts
   - after such a problems, the merits are not so clear, since the  
 usefulness can only really be attributed to two things:
      1. Standardising documentation of variable usage.
      2. Getting the compiler to help catch programmer errors.
    and some people claim that they have never found any bugs by using  
 const.
There are a lot of talk about const/readonly/immutability in the archives. I have to admit that I don't have the strenght to read them, so I didn't (yet anyway). C++ const is better than nothing. Hopefully there will be a solution that will suit everybody, more or less. C++ const has flaws, of course. Sometimes it's necessary to do non-const-casting inside a const member function. But 'const' tells that a function is logically const even if it's not physically (statically?) one. So for a programmer it's only documentation tool that a compiler can use to check for (some) programming errors. And as such it has been working fine, for me at least. (I don't know what this C++ const ugliness means. 'const' is a wrong word, so I don't use it? ;) )
Sep 12 2006
parent reply Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Tue, 12 Sep 2006 17:49:44 +0300, Kristian <kjkilpi gmail.com>
wrote:

C++ const is better than nothing. Hopefully there will be a solution that  
will suit everybody, more or less.
As far as the meaning of 'const' goes, I agree. It represents a specific, restricted meaning of 'const'. Choosing a reasonable word for an intended meaning does not mean that all possible meanings of that word must be valid. If you're going to fuss about keyword meanings, I'd focus on 'real', 'ireal' and 'creal'. 'Real' cannot handle irrational numbers, and it can't handle rationals properly either. It does not handle all possible meanings of 'real' - not even within a given range and precision, unless you define those terms in a floating-point specific way. And as for 'imaginary real' and 'complex real', the important phrase here is 'contradiction in terms'. The keywords convey an intended meaning. It's a matter of common sense. Being too literal gets you no-where. Being an Aspie, I have plenty of experience of this :-( But I have mixed feelings about C++ const. It has caught errors for me, but not often, and quite often those errors wouldn't exist without 'const' anyway. For instance... class c_Test { private: int m_Var; public: // int Var () const { return m_Var; } int& Var () { return m_Var; } }; The point of this is the 'missing' method. You can read the value of m_Var if you have a non-const reference to c_Test. Mark that reference as const, and suddenly you can no longer do the needed read access - you have to go back and add the const overloaded access method. Of course I understand the efficiency benefits, but it's not very intuitive. And there wouldn't have been any error using simple getter and setter functions instead of this C++ specific pattern. What's more, you can end up chasing your tail. You start with a few const references. Then more and more things need a const tag or a const variant as a result. Member functions. References. Pointers. Member pointers. Pointers even need to be told whether it is the pointer that is const or the value pointed to, or both for that matter. So the dependencies mean you have three options... 1. Make constness into something you think about all the time. 2. Don't do constness at all. 3. Do half-hearted constness and have loads of const-casts, defeating the point. And then, your code has to work with someone elses... Someone who has a very different approach. Personally, I tend towards case 1 - I can be a perfectionist at times. Trouble is, this can be a distraction from the real logic. And that can cause logical errors that wouldn't have happened if my attention hadn't been split. D has been a bit of a relief, really. -- Remove 'wants' and 'nospam' from e-mail.
Sep 13 2006
parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Steve Horne wrote:
 On Tue, 12 Sep 2006 17:49:44 +0300, Kristian <kjkilpi gmail.com>
 wrote:
 
 C++ const is better than nothing. Hopefully there will be a solution that  
 will suit everybody, more or less.
Lack of const and requiring people to document their code well is the only painless solution at the moment, I think. That, and switching to a pure functional language.
 
 But I have mixed feelings about C++ const. It has caught errors for
 me, but not often, and quite often those errors wouldn't exist without
 'const' anyway. 
How can you call that catching errors?
 Of course I understand the efficiency benefits, but it's not very
 intuitive.
As Walter says, the efficiency benefits are very small because of the aliasing problem and the presence of const_cast. The main two reasons for const are catching errors and documenting code.
 Pointers even need to be told whether it is the pointer that is const
 or the value pointed to, or both for that matter.
 
This is what I was talking about with the ugliness of const, not the naming system. const Fred const * p; is a bit excessive, don't you think? Not to mention very illegible. D's move to implicit reference semantics for classes means that we can get a generally-easier-to-read syntax, like is proposed in Javari: readonly final Fred p; where 'readonly' refers to the actual data, and 'final' means that p can't be used as an lval (ie, the pointer itself is const).
 So the dependencies mean you have three options...
 
 1.  Make constness into something you think about all the time.
 2.  Don't do constness at all.
 3.  Do half-hearted constness and have loads of const-casts,
     defeating the point.
 
 And then, your code has to work with someone elses... Someone who has
 a very different approach.
In a way, the choice is made on a language level, which is the concern about const in D. As you have described, it becomes a real nuisance in C++, and the benefits are not always clear. Just giving a taste of the discussions of const on this newsgroup... <g> Cheers, Reiner
Sep 13 2006
next sibling parent Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Wed, 13 Sep 2006 19:02:27 +1000, Reiner Pope
<reiner.pope REMOVE.THIS.gmail.com> wrote:

 But I have mixed feelings about C++ const. It has caught errors for
 me, but not often, and quite often those errors wouldn't exist without
 'const' anyway. 
How can you call that catching errors?
That's down to the definition of 'error', of course. Trying to call a non-const method for a const object is an error, by definition, in C++. The fact that you only wanted read a value is besides the point. Letter of the law vs. practical reality. Be careful what you say, or the language lawyers will come for you ;-) -- Remove 'wants' and 'nospam' from e-mail.
Sep 13 2006
prev sibling parent Kristian <kjkilpi gmail.com> writes:
On Wed, 13 Sep 2006 12:02:27 +0300, Reiner Pope  =

<reiner.pope REMOVE.THIS.gmail.com> wrote:
 Steve Horne wrote:
[snip]
 Pointers even need to be told whether it is the pointer that is const=
 or the value pointed to, or both for that matter.
This is what I was talking about with the ugliness of const, not the =
 naming system.

    const Fred const * p;
Yep, that one doesn't look nice. (And it's a bit confusing too.)
 is a bit excessive, don't you think? Not to mention very illegible. D'=
s =
 move to implicit reference semantics for classes means that we can get=
a =
   generally-easier-to-read syntax, like is proposed in Javari:

    readonly final Fred p;

 where 'readonly' refers to the actual data, and 'final' means that p  =
 can't be used as an lval (ie, the pointer itself is const).
That's indeed more readable. I woundn't mind using it or something simil= ar. From time to time I wish that C++ would have a readonly specifier that = = works like this: class Obj { void f() { int m_size =3D 10; //ok } readonly int m_size; } void func() { Obj o =3D new Obj; int v; v =3D o.m_size; //ok o.m_size =3D 5; //error } 'm_size' can be accessed inside 'Obj' as normal, but outside the class t= he = variable cannot be modified. Of course, I could provide a read property = = (that is, a function in C++) for accessing 'm_size' (in addition to a = write property), but when it's not necessary, this way is simplier (and = a = little bit faster, etc.). In D this, however, is not needed because you can use properties to wrap= = member variables. (Hopefully the properties will be extended to support the same methods = that can be applied to variables also... ;) )
Sep 14 2006
prev sibling parent reply Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Sun, 10 Sep 2006 22:03:43 +0300, Kristian <kjkilpi gmail.com>
wrote:

Maybe there should be two properties, .dup and .deepdup (or something,
a name .ddup is probably too similar).
How often is there more than one useful meaning for 'duplicate' for a particular class anyway? Shallow vs. deep vs. something in between is usually an implementation detail.
Really? I mean, a common source of bugs? But isn't it be simple to fix  
such bugs, just correct the copy methods?
I suspect this is about accidental copying. Parameter passing, implicit conversions, unexpected temporaries etc. I have an ideological disagreement against making references compulsory in a languages that has mutability (any imperitive language). You can easily get things being changed that weren't intended to be changed. You save info. for later, but the saved info. mutates because it wasn't a copy, for instance. In practice, it sometimes causes me hassles in Python, and probably would in Java if I used it much. references work well, for me. There seems to be an intuitive divide between 'object' and 'value'. For a 'value', I expect parameter passing to have copy semantics. For an 'object' I expect sharing (reference) semantics. Maybe it's something to do with the real world. It's just natural to work with existing objects - not duplicates of those objects. When I was told to clean my room as a child, I don't think stories about duplicating the room, cleaning the duplicate and discarding it would have worked ;-) With 'values' - numbers etc - copy semantics seem more sane. In algebra, calculating the unknowns does not alter the known values. Outputs are based on inputs, not the other way around. Even feedback has a time delay - the calculation of the output doesn't change its input, it just provides a new input for the next millisecond or whatever. The trouble is, this is all subjective. The Python one-size-fits-all everythings-an-object-with-a-reference approach will probably always bug me, but a lot depends on what you're used to. -- Remove 'wants' and 'nospam' from e-mail.
Sep 10 2006
next sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Steve Horne wrote:

 references work well, for me. There seems to be an intuitive divide
 between 'object' and 'value'. For a 'value', I expect parameter
 passing to have copy semantics. For an 'object' I expect sharing
 (reference) semantics.
 
 Maybe it's something to do with the real world. It's just natural to
 work with existing objects - not duplicates of those objects. When I
 was told to clean my room as a child, I don't think stories about
 duplicating the room, cleaning the duplicate and discarding it would
 have worked ;-)
 
 With 'values' - numbers etc - copy semantics seem more sane. In
 algebra, calculating the unknowns does not alter the known values.
 Outputs are based on inputs, not the other way around. Even feedback
 has a time delay - the calculation of the output doesn't change its
 input, it just provides a new input for the next millisecond or
 whatever.
Well said. I needed some time to adjust to the reference semantics of classes in D and it's less (than C++) capable struct type. But now I'm used to it, it really makes sense. Besides some minor details, in C++ a struct is the same as a class. But in D they really are different beasts, making the distinction and when to use which one easier. In C++ you have to think all the time about reference vs value semantics and take care of what happens in the assignment operator and copy constructor, and not only wrt memory allocation. Even though you don't have the standard syntactic sugar of struct construction and copying in D, the way it works now is intuitive enough and - imho - makes for a more productive and safe way of doing things. Assignment can be a dangerous operation and in D you can be sure of what happens at least.
Sep 11 2006
parent Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Mon, 11 Sep 2006 12:51:12 +0200, Lutger
<lutger.blijdestijn gmail.com> wrote:

Well said. I needed some time to adjust to the reference semantics of 
classes in D and it's less (than C++) capable struct type. But now I'm 
used to it, it really makes sense.
Yeah, I'm still adjusting too. Too used to being able to use inheritance to create extended structs in C++. Less bothered by having references for objects because I've done that before, but I still don't like having a tool taken out of my toolkit ;-) In code I'm writing at the moment, it's an issue, but a minor one. D has saved probably ten or more units of effort for this one that it has created. So while I made the relevant suggestions and defended them, it's probably not a big deal IMO. At the moment, I'm having trouble with interfaces. I can't seem to get the right patterns for using them. This is one of the things with a new language. Picking up the new syntax and semantics may not seem that hard, but putting it to work in a real project can be a pain - you end up in a refactoring loop, chasing your own tail until you find the patterns that work in that language. -- Remove 'wants' and 'nospam' from e-mail.
Sep 11 2006
prev sibling next sibling parent Kristian <kjkilpi gmail.com> writes:
On Mon, 11 Sep 2006 01:23:38 +0300, Steve Horne  
<stephenwantshornenospam100 aol.com> wrote:
[snip]
 Really? I mean, a common source of bugs? But isn't it be simple to fix
 such bugs, just correct the copy methods?
I suspect this is about accidental copying. Parameter passing, implicit conversions, unexpected temporaries etc.
Yes, these things could cause harm. I have had a few incidents with unxcepted temporaries (only few fortunately). [snip]
 Maybe it's something to do with the real world. It's just natural to
 work with existing objects - not duplicates of those objects. When I
 was told to clean my room as a child, I don't think stories about
 duplicating the room, cleaning the duplicate and discarding it would
 have worked ;-)

 With 'values' - numbers etc - copy semantics seem more sane. In
 algebra, calculating the unknowns does not alter the known values.
 Outputs are based on inputs, not the other way around. Even feedback
 has a time delay - the calculation of the output doesn't change its
 input, it just provides a new input for the next millisecond or
 whatever.

 The trouble is, this is all subjective. The Python one-size-fits-all
 everythings-an-object-with-a-reference approach will probably always
 bug me, but a lot depends on what you're used to.
Well said. Usually (I think/hope) objects are 'unique' with no need to copy them. You just have to adjust your thinking. However, sometimes 'working objects' are needed in calculations. But, as said, structures are for that. I am just wondering that should structures indeed have constructors and destructors. It would allow one to create more complex data types. Probably interfaces wouldn't hurt either. And another thing that I have no clear grasp yet is unability to copy/clone class objects. For example: class Obj; void func(Obj obj) { Obj tmp; tmp.clone(obj); //modify 'tmp' ... //use 'tmp' instead of 'obj' ... } Or you just need to store objects for later use. These things cannot be done currently. How often that would be necessary, in practice? (Once is enough to give you gray hair...?)
Sep 12 2006
prev sibling parent reply Tydr Schnubbis <fake address.dude> writes:
Steve Horne wrote:
 The trouble is, this is all subjective. The Python one-size-fits-all
 everythings-an-object-with-a-reference approach will probably always
 bug me, but a lot depends on what you're used to.
 
Not sure I follow. Python uses value semantics for numbers and strings. The reason you get them for strings is that strings are immutable, so Python always creates a copy when a string is about to be changed. So it works like in D, except for the strings.
Sep 12 2006
parent Steve Horne <stephenwantshornenospam100 aol.com> writes:
On Tue, 12 Sep 2006 23:33:39 +0200, Tydr Schnubbis <fake address.dude>
wrote:

Steve Horne wrote:
 The trouble is, this is all subjective. The Python one-size-fits-all
 everythings-an-object-with-a-reference approach will probably always
 bug me, but a lot depends on what you're used to.
 
Not sure I follow. Python uses value semantics for numbers and strings. The reason you get them for strings is that strings are immutable, so Python always creates a copy when a string is about to be changed. So it works like in D, except for the strings.
Sorry - I had a specific problem recently and got a bit annoyed and irrational. I've enough Python experience that I shouldn't have got confused this way, but I haven't used Python seriously for long enough that I did anyway :-( Everything is an object with a reference. Some things are immutable, so it shouldn't matter. But...
 a=5
 b=lambda :a
 b()
5
 a=6
 b()
6 According to the definition of a closure, the lambda should bind the value of a. It can't bind a link to the variable, since the variable might not exist when the lambda is evaluated. Yet there is clearly some kind of by-reference binding, or else why does assigning a new value to 'a' cause 'b' to give a different result. So why the above? Well, maybe a minor bug. Maybe a command-line-only thing. I haven't investigated. I was only using Python as a calculator when I tripped over the problem. D behaves similarly with anonymous functions and delegates, but that's because D inner functions etc don't support 'true' closures. In fact, D anonymous delegates aren't even valid after you leave the scope where they were defined. But that's not unexpected - a different convenience vs. efficiency trade-off. Python closures are supposed to be true closures. -- Remove 'wants' and 'nospam' from e-mail.
Sep 13 2006
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Kristian wrote:
 ...
Those "physical types", are called value types. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 22 2006
parent Kristian <kjkilpi gmail.com> writes:
On Sat, 23 Sep 2006 00:35:07 +0300, Bruno Medeiros  
<brunodomedeiros+spam com.gmail> wrote:

 Kristian wrote:
  > ...

 Those "physical types", are called value types.
Hehheh, so they are. Sometimes it's just too hard to come up with the correct term... ;)
Sep 23 2006