D - [opAssign] why no overload/forbidding for '='
- Manfred Nowak (34/34) Feb 10 2004 I am playing with a numerical class `number'.
- Roberto Mariottini (5/39) Feb 11 2004 You seem to have a point here.
- Ben Hinkle (52/52) Feb 11 2004 I'm not clear on the purpose of the trace field. My first suggestion is ...
- Stewart Gordon (23/38) Feb 11 2004 While it was 2/10/04 6:12 PM throughout the UK, Manfred Nowak sprinkled
- Sam McCall (7/20) Feb 11 2004 Maybe D needs a "copy" operator. For value types it would be a direct
- J Anderson (8/16) Feb 11 2004 I think it would be nice of have a deep and shallow assignment, since we...
- Matthias Becker (3/10) Feb 11 2004 Well, in Heron you two different operators, one to copy the object, one ...
- Stewart Gordon (18/25) Feb 11 2004 While it was 2/11/04 12:31 PM throughout the UK, Sam McCall sprinkled
- Walter (20/28) Jun 01 2004 Most of the assignment operator overloading in C++ seems to be needed to
- Daniel Horn (8/45) Jun 01 2004 What if you want your structs to really pass by value, or if you want to...
- Arcane Jill (11/14) Jun 01 2004 That should be harmless in this particular case, since Ints are immutabl...
- Arcane Jill (15/26) Jun 01 2004 I'm tempted to ask, then, why the operators +=, *=, ++, and so on, are a...
-
Stewart Gordon
(21/23)
Jun 02 2004
- Walter (8/17) Jun 02 2004 all
- hellcatv hotmail.com (6/26) Jun 02 2004 But what about overriding opAssign for structs...structs may or may not ...
- Arcane Jill (9/13) Jun 02 2004 Ah - well, I'm off topic for the thread title here, but just quickly to
- Walter (9/14) Jun 04 2004 from
- Arcane Jill (28/31) Jun 04 2004 Yes, you're probably right. I've been thinking the same thing. But I wou...
- Matthew (7/23) Jun 04 2004 to
- Walter (27/45) Jun 04 2004 be a
- Arcane Jill (32/42) Jun 04 2004 Forgive me - I don't understand the problem. The way I see it, a struct
- Kevin Bealer (18/25) Jun 04 2004 Using opCall for non-new applications is only confusing if you typically
-
Carlos Santander B.
(39/39)
Jun 04 2004
"Kevin Bealer"
escribió en el mensaje -
Arcane Jill
(11/14)
Jun 04 2004
- Ivan Senji (24/38) Jun 05 2004 opinion) is
- Kevin Bealer (3/17) Jun 05 2004 You're right.. sorry about that.
- Matthias Becker (7/20) Aug 09 2004 So your problem is that we break with a C++ idiom in D? Even if this wer...
- Matthias Becker (9/10) Aug 09 2004 Yes. new just doesn't make sense. It's more to type and it doesn't give ...
- J Anderson (11/15) Jun 05 2004 I've not problem with this (adding a constructor for structs). We all
- Arcane Jill (23/27) Aug 06 2004 So, two months have gone by since the above quote, and pretty much every...
- Matthias Becker (6/9) Aug 09 2004 I have no problim with not having destructors in structs.
- Arcane Jill (17/24) Aug 09 2004 Which would you prefer?
- Norbert Nemec (7/10) Jun 07 2004 Why do you want to do that on a per-object basis? The probably cleaner,
- Arcane Jill (3/13) Jun 07 2004 Did that a few hours ago.
- hellcatv hotmail.com (51/65) Jun 04 2004 what if you have a struct holding an item it was templatized on
- Norbert Nemec (20/38) Jun 07 2004 If BigInteger is implemented as a class containing a reference to the da...
- Arcane Jill (9/11) Jun 07 2004 I'm smarter than that.
- Norbert Nemec (20/20) Jun 01 2004 One other purpose of overloaded assignments in C++ not mentioned here ar...
- Kevin Bealer (4/34) Jun 02 2004 99% agreed, but objects that hold an open file, mmap, etc might want to ...
- Norbert Nemec (11/14) Jun 02 2004 There are two ways to interpret this statement:
- Kevin Bealer (9/23) Jun 02 2004 I would stipulate to classes.
- Walter (9/17) Jun 02 2004 to
- Norbert Nemec (16/17) Jun 02 2004 Can references to auto classes be handled (copied, used as argument,
- Walter (15/33) Jun 04 2004 an
I am playing with a numerical class `number'. First all ops and assigns were functions. Then I switched to overloading `+' and `*' to use number a, b, c; // `new number' omitted a= b + c; and changed my `unittest' cases accordingly. The trivial cases passed. Then some errors occurred and I decided to include a `trace' field in the class to allow tracing of the actions in a particular instance of `number' by stating for example: b.trace= true; a= b + c; This worked fine. However, when wanting to trace `a' by a.trace= true; a= b + c; I trapped into the mess: the `trace' field of `a' was overwritten by the `trace' field of `b + c' which of course was not set to `true'. So I wanted to overload `=' to not overwrite the trace field. No way because of the lack of `opAssign'. I had to include a property `set' to `number' and change all existing `=' to `.set='. That was not only a simple lexical change, because `=' was of course not only used for assigning to `number'. My number of test cases grew and I made intensive use of the trace feature. When getting a mysterious result I inserted a printout into a `while' loop to observe a local variable. But there was no output. Conclusion: the loop was not entered. Action: more outputs inserted into the enclosing scopes. Observation: no output. ... Final observation: did not use `.set=' but only `='. ARRGGGHHH! However, forbidding of the use of pure `=', for example by declaring it private, is also not possible. Any suggestions? So long.
Feb 10 2004
You seem to have a point here. And it seems that nobody has an idea. Anyone? Ciao In article <c0b6v5$1sel$1 digitaldaemon.com>, Manfred Nowak says...I am playing with a numerical class `number'. First all ops and assigns were functions. Then I switched to overloading `+' and `*' to use number a, b, c; // `new number' omitted a= b + c; and changed my `unittest' cases accordingly. The trivial cases passed. Then some errors occurred and I decided to include a `trace' field in the class to allow tracing of the actions in a particular instance of `number' by stating for example: b.trace= true; a= b + c; This worked fine. However, when wanting to trace `a' by a.trace= true; a= b + c; I trapped into the mess: the `trace' field of `a' was overwritten by the `trace' field of `b + c' which of course was not set to `true'. So I wanted to overload `=' to not overwrite the trace field. No way because of the lack of `opAssign'. I had to include a property `set' to `number' and change all existing `=' to `.set='. That was not only a simple lexical change, because `=' was of course not only used for assigning to `number'. My number of test cases grew and I made intensive use of the trace feature. When getting a mysterious result I inserted a printout into a `while' loop to observe a local variable. But there was no output. Conclusion: the loop was not entered. Action: more outputs inserted into the enclosing scopes. Observation: no output. ... Final observation: did not use `.set=' but only `='. ARRGGGHHH! However, forbidding of the use of pure `=', for example by declaring it private, is also not possible. Any suggestions? So long.
Feb 11 2004
I'm not clear on the purpose of the trace field. My first suggestion is to make the trace of the result of a binary operation be true if the trace of either input is true: result.trace = x.trace || y.trace; Remember objects are assigned by reference, not by copying the contents. I'd be surprised if overloading assignment is the best solution for your problem. -Ben "Manfred Nowak" <svv1999 hotmail.com> wrote in message news:c0b6v5$1sel$1 digitaldaemon.com... | I am playing with a numerical class `number'. | | First all ops and assigns were functions. | | Then I switched to overloading `+' and `*' to use | number a, b, c; // `new number' omitted | a= b + c; | and changed my `unittest' cases accordingly. The trivial cases passed. | Then some errors occurred and I decided to include a `trace' field in the | class to allow tracing of the actions in a particular instance of `number' | by stating for example: | b.trace= true; | a= b + c; | This worked fine. However, when wanting to trace `a' by | a.trace= true; | a= b + c; | I trapped into the mess: the `trace' field of `a' was overwritten by the | `trace' field of `b + c' which of course was not set to `true'. | | So I wanted to overload `=' to not overwrite the trace field. No way | because of the lack of `opAssign'. I had to include a property `set' to | `number' and change all existing `=' to `.set='. That was not only a | simple lexical change, because `=' was of course not only used for | assigning to `number'. | | My number of test cases grew and I made intensive use of the trace | feature. | | When getting a mysterious result I inserted a printout into a `while' loop | to observe a local variable. But there was no output. Conclusion: the loop | was not entered. Action: more outputs inserted into the enclosing scopes. | Observation: no output. ... | | Final observation: did not use `.set=' but only `='. ARRGGGHHH! | | However, forbidding of the use of pure `=', for example by declaring it | private, is also not possible. | | Any suggestions? | | So long. | | | |
Feb 11 2004
While it was 2/10/04 6:12 PM throughout the UK, Manfred Nowak sprinkled little black dots on a white screen, and they fell thus: <snip>I decided to include a `trace' field in the class to allow tracing of the actions in a particular instance of `number' by stating for example: b.trace= true; a= b + c;You already have a problem here. D is not C++. Object variables aren't the objects themselves, but references to them.This worked fine. However, when wanting to trace `a' by a.trace= true; a= b + c; I trapped into the mess: the `trace' field of `a' was overwritten by the `trace' field of `b + c' which of course was not set to `true'.No it wasn't. The object reference 'a' was overwritten with a reference to a whole new object.So I wanted to overload `=' to not overwrite the trace field. No way because of the lack of `opAssign'. I had to include a property `set' to `number' and change all existing `=' to `.set='. That was not only a simple lexical change, because `=' was of course not only used for assigning to `number'.<snip> The = operator on objects has a specific meaning as far as D is concerned - to copy object references, not the objects (or parts thereof) themselves. I think the only reason C++ allows overloading of = is that variables _are_ objects, not just references to them. Combining this with C++'s lack of GC, assignments sometimes need special handling. OTOH, in D, with its objects by reference and GC, being able to overload = was deemed pointless for anything but code obfuscation. Maybe you need to rethink your debug coding strategy. Or maybe someone else has an idea.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from being the victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Feb 11 2004
The = operator on objects has a specific meaning as far as D is concerned - to copy object references, not the objects (or parts thereof) themselves. I think the only reason C++ allows overloading of = is that variables _are_ objects, not just references to them. Combining this with C++'s lack of GC, assignments sometimes need special handling. OTOH, in D, with its objects by reference and GC, being able to overload = was deemed pointless for anything but code obfuscation. Maybe you need to rethink your debug coding strategy. Or maybe someone else has an idea....Maybe D needs a "copy" operator. For value types it would be a direct copy, for classes it would default to memberwise copy and be overridable. (Should it copy members using itself or using =?, ie shallow or deep copy? Not sure. Maybe _two_ operators ;-) Sam PS is this like what Heron does? I haven't had a chance to look at it yet.
Feb 11 2004
Sam McCall wrote:Maybe D needs a "copy" operator. For value types it would be a direct copy, for classes it would default to memberwise copy and be overridable. (Should it copy members using itself or using =?, ie shallow or deep copy? Not sure. Maybe _two_ operators ;-) Sam PS is this like what Heron does? I haven't had a chance to look at it yet.I think it would be nice of have a deep and shallow assignment, since we already have a deep and shallow comparison. Parhaps something along those lines. = //Shallow == //Deep -- -Anderson: http://badmama.com.au/~anderson/
Feb 11 2004
Maybe D needs a "copy" operator. For value types it would be a direct copy, for classes it would default to memberwise copy and be overridable. (Should it copy members using itself or using =?, ie shallow or deep copy? Not sure. Maybe _two_ operators ;-) Sam PS is this like what Heron does? I haven't had a chance to look at it yet.Well, in Heron you two different operators, one to copy the object, one to copy the reference itself. Eiffel has maechanisms for flat and deep copying.
Feb 11 2004
While it was 2/11/04 12:31 PM throughout the UK, Sam McCall sprinkled little black dots on a white screen, and they fell thus: <snip>Maybe D needs a "copy" operator. For value types it would be a direct copy, for classes it would default to memberwise copy and be overridable. (Should it copy members using itself or using =?, ie shallow or deep copy? Not sure. Maybe _two_ operators ;-) SamEven still, there are at least two ways that object copying could work: - filling in the members of the destination object with the copied data (similar to C++) - would probably add unnecessary complications to both the D implementor and the D programmer. - creating a copy as a new object (similar to Java clone, and D dup on things that support it) - wouldn't by itself solve the OP's problem without further complications. And if we did implement a deep copy operator, we'd also need to think about our multiple references and circular data structures.PS is this like what Heron does? I haven't had a chance to look at it yet.I see, another language that Foldoc still hasn't heard of. Maybe I'll look at it when I get the time.... -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Feb 11 2004
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message news:c0d3ti$22u6$1 digitaldaemon.com...The = operator on objects has a specific meaning as far as D is concerned - to copy object references, not the objects (or parts thereof) themselves. I think the only reason C++ allows overloading of = is that variables _are_ objects, not just references to them. Combining this with C++'s lack of GC, assignments sometimes need special handling. OTOH, in D, with its objects by reference and GC, being able to overload = was deemed pointless for anything but code obfuscation.Most of the assignment operator overloading in C++ seems to be needed to just keep track of who owns the memory. So by using reference types coupled with GC, most of this just gets replaced with copying the reference itself. For example, given an array of class objects, the array's contents can be moved, sorted, shifted, etc., all without any need for overloaded assignments. Ditto for function parameters and return values. The references themselves just get moved about. There just doesn't seem to be any need for copying the entire contents of one class object into another pre-existing class object. Sometimes, one does need to create a copy of a class object, and for that one can still write a copy constructor in D, but they just don't seem to be needed remotely as much as in C++. Structs, being value objects, do get copied about. A copy is defined in D to be a bit copy. I've never been comfortable with any object in C++ that does something other than a bit copy when copied. Most of this other behavior stems from that old problem of trying to manage memory. Absent that, there doesn't seem to be a compelling rationale for allowing anything other than a bit copy.
Jun 01 2004
What if you want your structs to really pass by value, or if you want to get consistent behavior with any template argument. For my BigRational struct it passes by value if you use an int or a long, but it passes by reference if you use a Int class (or some Int struct with an array) in the template. Likewise an assign is a deep copy with long, and a shallow copy with a class. It would be nice to get consistent behavior no matter the template argument. Walter wrote:"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message news:c0d3ti$22u6$1 digitaldaemon.com...The = operator on objects has a specific meaning as far as D is concerned - to copy object references, not the objects (or parts thereof) themselves. I think the only reason C++ allows overloading of = is that variables _are_ objects, not just references to them. Combining this with C++'s lack of GC, assignments sometimes need special handling. OTOH, in D, with its objects by reference and GC, being able to overload = was deemed pointless for anything but code obfuscation.Most of the assignment operator overloading in C++ seems to be needed to just keep track of who owns the memory. So by using reference types coupled with GC, most of this just gets replaced with copying the reference itself. For example, given an array of class objects, the array's contents can be moved, sorted, shifted, etc., all without any need for overloaded assignments. Ditto for function parameters and return values. The references themselves just get moved about. There just doesn't seem to be any need for copying the entire contents of one class object into another pre-existing class object. Sometimes, one does need to create a copy of a class object, and for that one can still write a copy constructor in D, but they just don't seem to be needed remotely as much as in C++. Structs, being value objects, do get copied about. A copy is defined in D to be a bit copy. I've never been comfortable with any object in C++ that does something other than a bit copy when copied. Most of this other behavior stems from that old problem of trying to manage memory. Absent that, there doesn't seem to be a compelling rationale for allowing anything other than a bit copy.
Jun 01 2004
In article <c9ingg$24uc$1 digitaldaemon.com>, Daniel Horn says...For my BigRational struct it passes by value if you use an int or a long, but it passes by reference if you use a Int classThat should be harmless in this particular case, since Ints are immutable, so copying a reference is safe in the sense that the original will never get clobbered. However, I agree with you completely on the general point. Sometimes you do need to copy by value.It would be nice to get consistent behavior no matter the template argument.I agree with you again. There should ideally be some consistent mechanism for copying by value. I don't care if it's opEquals, copy-constructor, dup method, my suggested := operator, or whatever, but there should be a way of copying by value that has the same syntax for *any* type. (And it should fail at compile-time if you try to copy-by-value a class for which dup() or copy constructor is not defined).
Jun 01 2004
In article <c9in1e$2461$1 digitaldaemon.com>, Walter says...Most of the assignment operator overloading in C++ seems to be needed to just keep track of who owns the memory. So by using reference types coupled with GC, most of this just gets replaced with copying the reference itself. For example, given an array of class objects, the array's contents can be moved, sorted, shifted, etc., all without any need for overloaded assignments. Ditto for function parameters and return values. The references themselves just get moved about. There just doesn't seem to be any need for copying the entire contents of one class object into another pre-existing class object.I'm tempted to ask, then, why the operators +=, *=, ++, and so on, are at all overloadable. It is a general expectation of programmers that the following sequence of statements:a = b; ++a;will not modify b. C++ achieves this by allowing the = in the first statement to be overloaded to copy by value. D doesn't, which is why I had to forbid such operators on Int. (A struct would not have sufficed because I needed to have a destructor). If, as you say, "There just doesn't seem to be any need for copying the entire contents of one class object into another pre-existing class object", then what need do we have of assigning operator overloads. It would make sense to ban them altogether, but continue to allow them for structs. ..and for structs, of course, opAssign() also makes sense. Arcane Jill
Jun 01 2004
Arcane Jill wrote: <snip>I'm tempted to ask, then, why the operators +=, *=, ++, and so on, are at all overloadable.<snip> Only postfix ++ and -- are overloadable. Prefix ++ and -- do the sensible thing. Just looking at the docs, " Assignment operator expressions, such as: a op= b are semantically equivalent to: a = a op b except that operand a is only evaluated once." Makes sense and is in line with C. But does this actually apply just as well if a is a class object, and doesn't have its own op<op>Assign? I guess that overloading is useful if you want to modify the object in place.... Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jun 02 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9iv40$2ftu$1 digitaldaemon.com...I'm tempted to ask, then, why the operators +=, *=, ++, and so on, are atalloverloadable. It is a general expectation of programmers that the following sequence of statements:statement toa = b; ++a;will not modify b. C++ achieves this by allowing the = in the firstbe overloaded to copy by value. D doesn't, which is why I had to forbidsuchoperators on Int.I got tripped up myself on this when I learned Java. Reference semantics are a different mindset, there's just no way around that. But once one gets comfortable with that different mindset, it isn't a problem anymore.
Jun 02 2004
But what about overriding opAssign for structs...structs may or may not have arrays inside...and this will determine whether they copy or not. case in point is my template class that accepts an Int or a long... depending on template arg the struct will do a shallow or deep copy I agree that classes should be consistent: but the same goes for structs. In article <c9l5ci$2ko3$2 digitaldaemon.com>, Walter says..."Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9iv40$2ftu$1 digitaldaemon.com...I'm tempted to ask, then, why the operators +=, *=, ++, and so on, are atalloverloadable. It is a general expectation of programmers that the following sequence of statements:statement toa = b; ++a;will not modify b. C++ achieves this by allowing the = in the firstbe overloaded to copy by value. D doesn't, which is why I had to forbidsuchoperators on Int.I got tripped up myself on this when I learned Java. Reference semantics are a different mindset, there's just no way around that. But once one gets comfortable with that different mindset, it isn't a problem anymore.
Jun 02 2004
In article <c9l836$2oob$1 digitaldaemon.com>, hellcatv hotmail.com says...But what about overriding opAssign for structs...structs may or may not have arrays inside...and this will determine whether they copy or not. case in point is my template class that accepts an Int or a long... depending on template arg the struct will do a shallow or deep copyAh - well, I'm off topic for the thread title here, but just quickly to mention... In the latest version I've actually removed the copy constructor and dup from Int, so you can't deep copy it any more. I did this because you don't need to deep copy it, ever, and I realized (in the end, after some prompting) that the presence of those functions might mislead people into thinking copy-by-value for this class did anything useful. Arcane Jill
Jun 02 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9la0f$2rpa$1 digitaldaemon.com...In the latest version I've actually removed the copy constructor and dupfromInt, so you can't deep copy it any more. I did this because you don't needtodeep copy it, ever, and I realized (in the end, after some prompting) thatthepresence of those functions might mislead people into thinkingcopy-by-value forthis class did anything useful.I've been thinking about the issue of BigInteger being implemented as a class, but desiring copy-by-value semantics. If you adopt the paradigm of copy-on-write for the internal array, wouldn't that achieve cbv semantics?
Jun 04 2004
In article <c9p8hq$2ja9$1 digitaldaemon.com>, Walter says...I've been thinking about the issue of BigInteger being implemented as a class, but desiring copy-by-value semantics. If you adopt the paradigm of copy-on-write for the internal array, wouldn't that achieve cbv semantics?Yes, you're probably right. I've been thinking the same thing. But I wouldn't have agreed with you until a few days' ago. You see, until a few days' ago, I would have considered that it *HAD* to be a class, because it is _unbelievably_ important to me that I am able to wipe memory after use (though only in a version(Secure) build, obviously - no need to give that performance hit to those who don't need it). Until a few days ago, I believed that having a destructor was the way to achieve that. But things have changed. You've told me that a destructor need not run. (In which case, I still don't see the point of allowing them! I'd still like for you to expand on this) Now that I know that, the decision to use a class becomes less clear. It is apparent that in the future I will have to write my own secure memory handler. That's ok - I've stuff like that before. But given that such a rewrite is on the cards, there is no longer any reason to keep it as a class. So yes, I could fairly easily change it to a struct - and this would have the added benefit of allowing me to implement +=, -=, ++ and so forth. But, Walter - structs don't have constructors, remember? So, that would leave me with no choice but to overload static opCall() to achieve the same effect. And while this would have the (rather nice) benefit of causing the word "new" to disappear from people's source code in relevant places - I rather thought you didn't like this approach. I mean, we're ending up with SOME things getting constructed with the syntax A(), OTHER things getting constructed with new A(), and YET MORE things offering both options. This is surely going to be confusing to people. Perhaps you might consider adopting my suggestion of making the keyword "new" optional in all cases, merging the functions of this() and static opCall(), and allowing structs to have constructors? Jill
Jun 04 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9p9ut$2lbr$1 digitaldaemon.com...In article <c9p8hq$2ja9$1 digitaldaemon.com>, Walter says...toI've been thinking about the issue of BigInteger being implemented as a class, but desiring copy-by-value semantics. If you adopt the paradigm of copy-on-write for the internal array, wouldn't that achieve cbv semantics?Yes, you're probably right. I've been thinking the same thing. But I wouldn't have agreed with you until a few days' ago. You see, until a few days' ago, I would have considered that it *HAD* to be a class, because it is _unbelievably_ important to me that I am able to wipe memory after use (though only in a version(Secure) build, obviously - no needgive that performance hit to those who don't need it). Until a few days ago, I believed that having a destructor was the way to achieve that. But things have changed. You've told me that a destructor need not run. (In which case, I still don't see the point of allowing them! I'd still like foryouto expand on this)If your class is auto, then it will. However, auto currently has quite a restrictive use. Although that's likely to be relaxed in the future, it still may not be as general purpose as you require.
Jun 04 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9p9ut$2lbr$1 digitaldaemon.com...You see, until a few days' ago, I would have considered that it *HAD* tobe aclass, because it is _unbelievably_ important to me that I am able to wipe memory after use (though only in a version(Secure) build, obviously - noneed togive that performance hit to those who don't need it). Until a few daysago, Ibelieved that having a destructor was the way to achieve that. But things have changed. You've told me that a destructor need not run.(Inwhich case, I still don't see the point of allowing them! I'd still likefor youto expand on this)Lazy destruction, which happens in gc, is pretty much useless for things that *must* be deleted. A more aggressive scheme is required, such as I outlined before. But lazy destructors still are very handy for debugging and logging purposes.But, Walter - structs don't have constructors, remember? So, that wouldleave mewith no choice but to overload static opCall() to achieve the same effect.Andwhile this would have the (rather nice) benefit of causing the word "new"todisappear from people's source code in relevant places - I rather thoughtyoudidn't like this approach. I mean, we're ending up with SOME thingsgettingconstructed with the syntax A(), OTHER things getting constructed with newA(),and YET MORE things offering both options. This is surely going to beconfusingto people. Perhaps you might consider adopting my suggestion of making the keyword "new" optional in all cases, merging the functions of this() andstaticopCall(), and allowing structs to have constructors?The trouble with allowing structs to have constructors, is then there's the issue of overloadable assignment operators and the default copy constructor, both of which I avoid. Then if there are constructors, why not destructors, and the whole complicated C++ mess appears (think what happens when you pass a struct as a function parameter). If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.
Jun 04 2004
In article <c9qiqn$1i01$1 digitaldaemon.com>, Walter says...The trouble with allowing structs to have constructors, is then there's the issue of overloadable assignment operators and the default copy constructor, both of which I avoid. Then if there are constructors, why not destructors, and the whole complicated C++ mess appears (think what happens when you pass a struct as a function parameter).Forgive me - I don't understand the problem. The way I see it, a struct constructor would just be an initialization function. It would function pretty much exactly like static opCall() does now. Overloadable assignment operators? You're talking about the much-discussed opAssign(), right? Ok - I *DO* see the problem. (I get there in the end). This is about parameter passing, right? If you pass a struct by value to a function, anything more complex than bit-copying is a pain in the neck. So you don't want opAssign(). Is that the problem?.If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.I don't have a problem with that at all. Structs should not have destructors, and I can think of a lot of reasons to justify that, but I don't see a problem with CONstructors. Like I said, people are using static opCall() for that very purpose right now, just to overcome that limitation (with the result of a nicer syntax even). And of course, if you ban destructors, then you also implicitly ban RAII. Goes without saying. Well, the way I see it is, if you give us constructors for structs, nobody is going to complain. (They might want more, but that's irrelevant). But wait - there's still something I'm not getting. Even if you do provide constructors for structs, why should anyone bother with them? What's the advantage over static opCall()? I mean, consider the following two lines:A a = A(parameters); A a = new A(parameters);There are undoubtedly people who are going to prefer the first syntex. (I'm one of them). Now I'm starting to wonder why I should bother with constructors even for classes, when I can get the nicer syntax for those, too, with static opCall() instead. What's worse, though, is that it is currently possible for people to implement both syntaxes in a class AND HAVE THEM DO COMPLETELY DIFFERENT THINGS. I think this is a dangerous idea, and that the two functions really should be merged into one, so that "new" then becomes optional at the whim of the caller, instead of (as now) optional at the whim of the class designer. I hope this helps. I'm not just nitpicking because I don't like "new". Jill
Jun 04 2004
In article <c9qkjv$1ko4$1 digitaldaemon.com>, Arcane Jill says... ..What's worse, though, is that it is currently possible for people to implement both syntaxes in a class AND HAVE THEM DO COMPLETELY DIFFERENT THINGS. I think this is a dangerous idea, and that the two functions really should be merged into one, so that "new" then becomes optional at the whim of the caller, instead of (as now) optional at the whim of the class designer. I hope this helps. I'm not just nitpicking because I don't like "new". JillUsing opCall for non-new applications is only confusing if you typically overload the opCall to mean "new". The normal use of opCall (in my opinion) is as a "functor", i.e. "operator()" in C++. Suppose I have a function: flip(int a) { .. } ..and code that calls it. I can make it into an object, which is then used as a function, but also holds state and may have other methods. This ability to tack state, ie member vars, onto a function by converting into a class and using it as a functor is useful to a lot of folks. The C++ STL for example is designed to allow functors in almost all places where a function would otherwise be used. Your opCall syntax conflicts with that idiom. If the conflict between syntaxes is dangerous, then maybe you should switch to the side of the road that (almost) everyone else is driving on? Kevin
Jun 04 2004
"Kevin Bealer" <Kevin_member pathlink.com> escribió en el mensaje news:c9qm08$1mkv$1 digitaldaemon.com | Using opCall for non-new applications is only confusing if you typically | overload the opCall to mean "new". The normal use of opCall (in my opinion) is | as a "functor", i.e. "operator()" in C++. Suppose I have a function: | | flip(int a) | { | .. | } | | ..and code that calls it. I can make it into an object, which is then used as | a function, but also holds state and may have other methods. | | This ability to tack state, ie member vars, onto a function by converting into a | class and using it as a functor is useful to a lot of folks. The C++ STL for | example is designed to allow functors in almost all places where a function | would otherwise be used. Your opCall syntax conflicts with that idiom. | | If the conflict between syntaxes is dangerous, then maybe you should switch to | the side of the road that (almost) everyone else is driving on? | | Kevin Not really. The following compiles just fine: class A { static void opCall () {} void opCall (int a) {} } Notice that they don't take the same arguments. If they do, then there's a compiler error about both functions conflicting, but I think that's a bug. ----------------------- Carlos Santander Bernal
Jun 04 2004
In article <c9qm08$1mkv$1 digitaldaemon.com>, Kevin Bealer says...Using opCall for non-new applications is only confusing if you typically overload the opCall to mean "new". The normal use of opCall (in my opinion) is as a "functor", i.e. "operator()" in C++.<snip> I am perfectly well aware of that. I have been using functors for a very long time. There are one or two in Int, come to think of it. But you're talking about /non-static/ opCall. Believe it or not, in the D world, there is a /static/ opCall. This is somewhat pointless, since a static functor is just - well - a function. And because it looks so much like a constructor, and because structs don't have constructors, that's what gets used, despite the fact that it wasn't designed for that purpose. Arcane Jill
Jun 04 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9rq7c$a78$1 digitaldaemon.com...In article <c9qm08$1mkv$1 digitaldaemon.com>, Kevin Bealer says...opinion) isUsing opCall for non-new applications is only confusing if you typically overload the opCall to mean "new". The normal use of opCall (in mylongas a "functor", i.e. "operator()" in C++.<snip> I am perfectly well aware of that. I have been using functors for a verytime. There are one or two in Int, come to think of it. But you're talking about /non-static/ opCall. Believe it or not, in the D world, there is a /static/ opCall. This issomewhatpointless, since a static functor is just - well - a function. And becauseitlooks so much like a constructor, and because structs don't haveconstructors,that's what gets used, despite the fact that it wasn't designed for that purpose.D also has other operators in static versions: so it is possible to do something like: class A { static int opAdd(char[] x){} } and then you us it: A + "some string"; Having static operators IMO is a good thing because it gives us a flexibility in writing code. Someone might find it useful to define static opCall to do something other that constructing, so why not. The problem would be solved by letting structs have constructors (also not asking for destructors) and then there would be no confusion: use new to construct, and static opCall (if you need it) for something else.Arcane Jill
Jun 05 2004
In article <c9rq7c$a78$1 digitaldaemon.com>, Arcane Jill says...In article <c9qm08$1mkv$1 digitaldaemon.com>, Kevin Bealer says...You're right.. sorry about that. KevinUsing opCall for non-new applications is only confusing if you typically overload the opCall to mean "new". The normal use of opCall (in my opinion) is as a "functor", i.e. "operator()" in C++.<snip> I am perfectly well aware of that. I have been using functors for a very long time. There are one or two in Int, come to think of it. But you're talking about /non-static/ opCall. Believe it or not, in the D world, there is a /static/ opCall. This is somewhat pointless, since a static functor is just - well - a function. And because it looks so much like a constructor, and because structs don't have constructors, that's what gets used, despite the fact that it wasn't designed for that purpose. Arcane Jill
Jun 05 2004
Using opCall for non-new applications is only confusing if you typically overload the opCall to mean "new". The normal use of opCall (in my opinion) is as a "functor", i.e. "operator()" in C++. Suppose I have a function: flip(int a) { .. } ..and code that calls it. I can make it into an object, which is then used as a function, but also holds state and may have other methods. This ability to tack state, ie member vars, onto a function by converting into a class and using it as a functor is useful to a lot of folks. The C++ STL for example is designed to allow functors in almost all places where a function would otherwise be used. Your opCall syntax conflicts with that idiom.So your problem is that we break with a C++ idiom in D? Even if this were true, it would be stupid. But you forgot the small keyword "static". So the C++ idiom doesn't conflict with our "idiom" that you can find in a lot more languages than just one. Remember: We want: "Foo()" instead of "new Foo()". In C++ you already have this if you constuct on the stack! -- Matthias Becker
Aug 09 2004
I'm not just nitpicking because I don't like "new".Yes. new just doesn't make sense. It's more to type and it doesn't give any usefull information. In C++ you need new. .. = new Foo() // constructed on the heap .. = Foo() // constructed on the stack There are many languages, where you can construct things without new and everybody is happy with it. Why is "new" there in D? I never understood it. I didn't in Java, eigther. -- Matthias Becker
Aug 09 2004
Walter wrote:If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.I've not problem with this (adding a constructor for structs). We all see structs as a light weight class so we don't want these other things in them anyway. I think this should be looked on from a practical stand-point (what will make this language better), rather then how to prevent arguments about the language (ie if this feature is left out then no-one can claim that D is flawed). Java left out pointers, so no-one can argue against all the evils of pointers but then no-one can make use of pointers in java either. -- -Anderson: http://badmama.com.au/~anderson/
Jun 05 2004
In article <c9qiqn$1i01$1 digitaldaemon.com>, Walter says...The trouble with allowing structs to have constructors, is <snip> If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.So, two months have gone by since the above quote, and pretty much everyone has said they could live with 1), 2) and 3). And now we have constructors for primitives. You see where this is leading...? The thing that we really need for generic programming, though, is consistency. As near as possible - the same syntax for all types. Consider the follwing possible D statements: (1) T x = new T(); (2) T* x = new T(); (3) T x = T(); (1) is appropriate for classes only; (2) is appropriate for primitives allocated on the heap only; (3) is appropriate for either structs or classes which happen to have overridden static opCall(). This is very counterintuitive. So, how hard would it be to make something like: construct all types, as it does in C++? (Oh, and to have initialize x to 5, not 0, as it does in C++)? I'm not too bothered about the exact syntax (althernatives have been suggested by others), only that the syntax be the same for everything. Oh, and primitives and structs should still end up on the stack, not the heap - it's not /allocating/ them that's desirable, it's /initializing/ them (with consistent syntax). Arcane Jill
Aug 06 2004
If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.I have no problim with not having destructors in structs. I'm not sure if I like 2). Why is it important? Imagine you have some caches for lazy evaluation or what ever. But hey, when we get C'tors for not having user defined assignment operatos (which we currently don't have too) I can live with that. And doesn't 1) imply 3)?
Aug 09 2004
In article <cf7liq$i01$1 digitaldaemon.com>, Matthias Becker says...If everyone would be satisfied with 1) no destructors and 2) bit copies for assignment and copy constructor and 3) no RAII for structs, I would be much more amenable to adding them in <g>.I have no problim with not having destructors in structs. I'm not sure if I like 2).Which would you prefer? (a) no constructors for structs, at all, ever. (b) constructors for structs, but no bitwise copying. Remember - there is no (c). There is no third alternative - not according to Walter's quote above. You may think you're arguing for (c), but you're not. Walter's quote implies that only (a) and (b) are on offer. Nothing else. No other choice. If you reject (b), the only choice left is (a). And I suspect you didn't want inadvertantly to vote for that.Why is it important?Squillions of reasons: temporary results; returning values from functions; the list is endless. Also, recall that in C++, operator=() is effectively equivalent to a destructor call followed by a constructor call (and in some cases is actually implemented that way). But if we're ruling out destructors, what would opAssign() do that a constructor didn't?And doesn't 1) imply 3)?Yes. But (3) doesn't imply (1). Maybe Walter was expecting some folk to say "we want destructors but not RAII" or something. That didn't happen. Jill
Aug 09 2004
Arcane Jill wrote:You see, until a few days' ago, I would have considered that it *HAD* to be a class, because it is _unbelievably_ important to me that I am able to wipe memory after useWhy do you want to do that on a per-object basis? The probably cleaner, easier and more secure way might be to use a different allocator for the critical data: This allocator would then just place all sensitive data in an isolated block of memory. As soon as the critical portion of your code is over, you can simply wipe that block completely with an explicit command.
Jun 07 2004
In article <ca151q$1st0$1 digitaldaemon.com>, Norbert Nemec says...Arcane Jill wrote:Did that a few hours ago. JillYou see, until a few days' ago, I would have considered that it *HAD* to be a class, because it is _unbelievably_ important to me that I am able to wipe memory after useWhy do you want to do that on a per-object basis? The probably cleaner, easier and more secure way might be to use a different allocator for the critical data: This allocator would then just place all sensitive data in an isolated block of memory. As soon as the critical portion of your code is over, you can simply wipe that block completely with an explicit command.
Jun 07 2004
what if you have a struct holding an item it was templatized on struct holder(T){ T value; holder opAdd(...) {...} } then each time you assign to the struct you have to do some sort of templatized copy of it that's specialized for each kind of T it can hold perhaps it holds a capital Int, perhaps some other class that needs some duplication... perhaps a long or an int or float. suddenly you need a million different specializations to construct the class template Constructor(T) { T makeSomething(T inp) { return new T(inp); } } template Constructor (T:mystruct) { T makeSomething(T inp) { return T(inp); } } template Constructor (T:float) { float makeSoemthing (float inp) { return inp; } ... and then the list goes on for all floats, ints, structs you might use... each time a new primitive type is added you have to update your template specializations. is there any way we could templatize on construction mechanism or on whether it's a class or on whether it's a reference. Another problem I'm facing is that my BigRational struct cannot have valid values initially: it's faced with 2 null Integers, because a struct cannot be assigned a class in its initial assignment phase. I would enjoy having some sort of constructor run when the struct was created so I could make the numerator a new Int(0) and the denominator a new Int(1); there's no no way to do this using the struct Rational (T){ T numerator= ...; T denom = ...; .. }; it has been the source of a number of bugs... especially in the case that T happens to be a long--because since it has to work for Int as well as Long, the denominator gets assigned an (illegal) value of zero since I cannot assign the denom to a default value of Constructor!(T).makeValue(1); any ideas for a good solution to this y'all? it would be nice if the language offered me something like this. it seems as if structs are simply incomplete without a way to set a reasonable default value that the compiler does not deign to see as a "constant value" In article <c9p8hq$2ja9$1 digitaldaemon.com>, Walter says..."Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9la0f$2rpa$1 digitaldaemon.com...In the latest version I've actually removed the copy constructor and dupfromInt, so you can't deep copy it any more. I did this because you don't needtodeep copy it, ever, and I realized (in the end, after some prompting) thatthepresence of those functions might mislead people into thinkingcopy-by-value forthis class did anything useful.I've been thinking about the issue of BigInteger being implemented as a class, but desiring copy-by-value semantics. If you adopt the paradigm of copy-on-write for the internal array, wouldn't that achieve cbv semantics?
Jun 04 2004
Walter wrote:"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:c9la0f$2rpa$1 digitaldaemon.com...If BigInteger is implemented as a class containing a reference to the data, this will not work: If you do a copy on write, this will change the reference inside the object, but other locations in the code might still hold a reference to the same object, so their value will be changed as well. What you would have to do, is copy-on-write for the whole object. For example: ------------------ class BigInteger { opAdd(BigInteger other) { BigInteger res = new BigInteger; res.value = ...; return res; } } ------------------ I don't even know, whether this should be called "copy-on-write" at all. It is more like considering BigInteger objects as read-only once they are constructed.In the latest version I've actually removed the copy constructor and dupfromInt, so you can't deep copy it any more. I did this because you don't needtodeep copy it, ever, and I realized (in the end, after some prompting) thatthepresence of those functions might mislead people into thinkingcopy-by-value forthis class did anything useful.I've been thinking about the issue of BigInteger being implemented as a class, but desiring copy-by-value semantics. If you adopt the paradigm of copy-on-write for the internal array, wouldn't that achieve cbv semantics?
Jun 07 2004
In article <ca14k2$1rlj$1 digitaldaemon.com>, Norbert Nemec says...If BigInteger is implemented as a class containing a reference to the data, this will not work:I'm smarter than that. When I said "implement copy by value semantics" you should implicitly read into my words "and make it work". I know how array references are stored, and how to play with them. Jill PS. The class is called Int. The phrase "big integer" is a suitable description, but it is not the name of the class, and should not be capitalized or concatenated.
Jun 07 2004
One other purpose of overloaded assignments in C++ not mentioned here are implicit type conversions: --------- onetype A; anothertype B = A; // will call the constructor anothertype::anothertype(onetype) B = A; // will call the assignment anothertype::operator=(onetype) --------- I don't have this matter completely sorted out for D, but it seems constructors for structs are a badly missing feature. Having both constructors and overloaded assignments would probably not be necessary (I've never seen anything useful but just duplicated code there in C++.) But one of the two definitely would be needed. Rationale: The expression template technique needs rather intelligent assignements to work. Actually, all the action happens on assignment/conversion. The whole expression is built up as one tree-structure and only in the end it is decided how it should be calculated. Without overloadable assignment/conversion, this will not be possible.
Jun 01 2004
In article <c9in1e$2461$1 digitaldaemon.com>, Walter says..."Stewart Gordon" <smjg_1998 yahoo.com> wrote in message news:c0d3ti$22u6$1 digitaldaemon.com...99% agreed, but objects that hold an open file, mmap, etc might want to at least handle the "I've been dupped" case, i.e. make a note not to close the file. KevinThe = operator on objects has a specific meaning as far as D is concerned - to copy object references, not the objects (or parts thereof) themselves. I think the only reason C++ allows overloading of = is that variables _are_ objects, not just references to them. Combining this with C++'s lack of GC, assignments sometimes need special handling. OTOH, in D, with its objects by reference and GC, being able to overload = was deemed pointless for anything but code obfuscation.Most of the assignment operator overloading in C++ seems to be needed to just keep track of who owns the memory. So by using reference types coupled with GC, most of this just gets replaced with copying the reference itself. For example, given an array of class objects, the array's contents can be moved, sorted, shifted, etc., all without any need for overloaded assignments. Ditto for function parameters and return values. The references themselves just get moved about. There just doesn't seem to be any need for copying the entire contents of one class object into another pre-existing class object. Sometimes, one does need to create a copy of a class object, and for that one can still write a copy constructor in D, but they just don't seem to be needed remotely as much as in C++. Structs, being value objects, do get copied about. A copy is defined in D to be a bit copy. I've never been comfortable with any object in C++ that does something other than a bit copy when copied. Most of this other behavior stems from that old problem of trying to manage memory. Absent that, there doesn't seem to be a compelling rationale for allowing anything other than a bit copy.
Jun 02 2004
Kevin Bealer wrote:99% agreed, but objects that hold an open file, mmap, etc might want to at least handle the "I've been dupped" case, i.e. make a note not to close the file.There are two ways to interpret this statement: 1. If you are talking about structs, then this approach would mean that you also need struct destructors. This again means lots of overhead and complications when copying around data (like for arguments, etc) 2. If you are talking about classes, this may either mean a) keeping track of references - again lots of overhead when copying around b) copying objects - in this case it is no problem keeping track of copies. Every construction and destruction of an object goes along with the call of constructors and destructors.
Jun 02 2004
In article <c9k15j$10kr$1 digitaldaemon.com>, Norbert Nemec says...Kevin Bealer wrote:I would stipulate to classes. Okay... I was actually thinking of manually calling "close()", but I thought that the .dup was provided as a "byte level copy" for all object types, but I just checked and you have to define a property if you want that on your own classes. My bad. My hypothetical "file" class could define ".dup" to do a "dup2()" on the file descriptor if necessary. Kevin99% agreed, but objects that hold an open file, mmap, etc might want to at least handle the "I've been dupped" case, i.e. make a note not to close the file.There are two ways to interpret this statement: 1. If you are talking about structs, then this approach would mean that you also need struct destructors. This again means lots of overhead and complications when copying around data (like for arguments, etc) 2. If you are talking about classes, this may either mean a) keeping track of references - again lots of overhead when copying around b) copying objects - in this case it is no problem keeping track of copies. Every construction and destruction of an object goes along with the call of constructors and destructors.
Jun 02 2004
"Kevin Bealer" <Kevin_member pathlink.com> wrote in message news:c9juaj$rir$1 digitaldaemon.com...toStructs, being value objects, do get copied about. A copy is defined in Ddoesbe a bit copy. I've never been comfortable with any object in C++ thattheresomething other than a bit copy when copied. Most of this other behavior stems from that old problem of trying to manage memory. Absent that,than adoesn't seem to be a compelling rationale for allowing anything otherleastbit copy.99% agreed, but objects that hold an open file, mmap, etc might want to athandle the "I've been dupped" case, i.e. make a note not to close thefile. In such cases, an auto class should fill the bill instead of a struct.
Jun 02 2004
Walter wrote:In such cases, an auto class should fill the bill instead of a struct.Can references to auto classes be handled (copied, used as argument, returned, etc.) at all? I have not tried it, but from what I understand, an auto-object would have to be bound to exactly one reference variable, otherwise, it will not be clear when it should be deleted. Thinking about it, I realize, that I do not really understand auto variables at all: is it correct that only that object is deleted which is referenced the moment in which the variable goes out of scope? So, if I create an object of an auto class and then assign zero to the variable, the object will stay on the heap to be garbage-collected? So the "auto" keyword would not give you any security except for saving you the explicit "delete" at every exit point of the block? One more reason to abolish the concept of auto-classes! Auto-variables are a nice convenience, but if they don't add any security that the object really is deleted, then auto-classes are a pure nuisance, restricting the use of a class without adding value in terms of security.
Jun 02 2004
"Norbert Nemec" <Norbert.Nemec gmx.de> wrote in message news:c9ldq4$39$1 digitaldaemon.com...Walter wrote:anIn such cases, an auto class should fill the bill instead of a struct.Can references to auto classes be handled (copied, used as argument, returned, etc.) at all? I have not tried it, but from what I understand,auto-object would have to be bound to exactly one reference variable, otherwise, it will not be clear when it should be deleted.An auto reference can be passed as a function argument.Thinking about it, I realize, that I do not really understand autovariablesat all: is it correct that only that object is deleted which is referenced the moment in which the variable goes out of scope?Yes.So, if I create an object of an auto class and then assign zero to the variable, the object will stay on the heap to be garbage-collected? So the "auto" keyword would not give you any security except for saving you the explicit "delete" at every exit point of the block?The compiler will insert a 'delete' on the reference at every exit point of the block, including exception unwinding. However, if you're clever and manage to have a copy of that reference 'leak' beyond the close of the local scope, it will be pointing to deleted data, and will cause a crash.One more reason to abolish the concept of auto-classes! Auto-variables areanice convenience, but if they don't add any security that the objectreallyis deleted, then auto-classes are a pure nuisance, restricting the use ofaclass without adding value in terms of security.They're just as secure as class objects on the stack in C++ are, in fact, even more secure.
Jun 04 2004