digitalmars.D - All right, all right! Interim decision regarding qualified Object
- Andrei Alexandrescu (38/38) Jul 11 2012 Required reading prior to this: http://goo.gl/eXpuX
- Mehrdad (9/12) Jul 11 2012 Referenced post (for context):
- travert phare.normalesup.org (Christophe Travert) (9/24) Jul 12 2012 const has no problem. It is bitwise const, and it works like that.
- Chris NS (6/6) Jul 11 2012 I say: finally. I've long felt that Object was already too
- Timon Gehr (18/58) Jul 11 2012 Thank you for taking the time.
- travert phare.normalesup.org (Christophe Travert) (32/49) Jul 12 2012 It's not worse thant breaking all code that overrides opEqual by
- Jonathan M Davis (48/49) Jul 12 2012 If you can figure out how to make this work, it's fine by me.
- Mehrdad (4/6) Jul 12 2012 How would we expect people to deal with these const issues when
- Jonathan M Davis (12/20) Jul 12 2012 The issue that we're trying to solve here is making opEquals, opCmp, toH...
- Mehrdad (14/22) Jul 12 2012 Depends on what you mean by 'need' I guess? You can either get
- Steven Schveighoffer (4/6) Jul 12 2012 Because you have no choice what your base class is -- Object. And if
- Jonathan M Davis (19/22) Jul 12 2012 You can use const and OOP together just fine, but that means that if you...
- Mehrdad (9/12) Jul 12 2012 Say person X who develops a class A with a const member similar
- Mike Parker (4/15) Jul 12 2012 Again, it's a matter of choice. You can always choose to use a
- Mehrdad (2/6) Jul 12 2012 You mean, "how do you choose *not* to use opEquals()?"?
- Jonathan M Davis (6/13) Jul 12 2012 Yes. Restrictions placed on Object affect _everyone_ using the language,...
- Mehrdad (2/6) Jul 12 2012 You mean, "how do you choose *not* to use opEquals()?"?
- Jonathan M Davis (19/41) Jul 12 2012 Exactly.
- Mehrdad (15/23) Jul 12 2012 Surely that's a non sequitur... Aren't we modifying druntime here?
- Steven Schveighoffer (17/32) Jul 12 2012 First, Object (and the functions in object_.d) is treated specially by t...
- Mehrdad (8/19) Jul 12 2012 Thanks for providing the link, I'll take a look at it. I'd never
- Jonathan M Davis (17/26) Jul 12 2012 druntime is the runtime for D. The compiler uses it to implement key asp...
- Walter Bright (2/7) Jul 12 2012 A main motivation for going this route is to avoid breaking existing cod...
- Jonathan M Davis (6/14) Jul 12 2012 Except that it's _guaranteed_ to break code, because anything which reli...
- deadalnix (7/21) Jul 12 2012 I'd advocate that rely on Object isn't a wise idea anyway. I've worked
- Walter Bright (2/8) Jul 12 2012 Which is why we'll be leaving those members in Object for the foreseeabl...
- Jacob Carlborg (7/25) Jul 12 2012 All containers in Tango are templated classes, interfaces or structs.
- Andrei Alexandrescu (24/33) Jul 12 2012 I've been thinking more about this and it's possible to keep good
- Daniel Kozak (3/45) Jul 12 2012 +1
- Steven Schveighoffer (9/48) Jul 12 2012 Hm... I don't like this, it slows down a very basic function.
- Roman D. Boiko (2/19) Jul 12 2012
- Roman D. Boiko (3/3) Jul 12 2012 On Thursday, 12 July 2012 at 13:41:52 UTC, Roman D. Boiko wrote:
- Andrei Alexandrescu (4/56) Jul 12 2012 Too complicated. I think we can afford one comparison.
- bearophile (4/5) Jul 12 2012 An annotation for old style classes?
- Roman D. Boiko (5/6) Jul 12 2012 One comparison for each of these basic usages. Would branch
- deadalnix (3/55) Jul 12 2012 And one branching. In itself it isn't high cost, but can become a
- Andrei Alexandrescu (5/7) Jul 12 2012 Cost should be assessed in comparison to the baseline work that is being...
- Steven Schveighoffer (10/68) Jul 12 2012 I don't know if it's one comparison, and really, we are doubling the
- Andrei Alexandrescu (3/7) Jul 12 2012 I think we'll find ways to deprecate them later.
- Jacob Carlborg (11/16) Jul 12 2012 Wouldn't the default be to inherit from Object?
- Steven Schveighoffer (15/29) Jul 12 2012 Many (most?) classes never care about opHash, opCmp, opEquals and
- Andrei Alexandrescu (3/5) Jul 12 2012 Well I wasn't keen on eliminating the four methods and look what happene...
- Steven Schveighoffer (18/23) Jul 12 2012 My personal opinion is we should simply eliminate the four methods (or a...
- Jonathan M Davis (9/13) Jul 12 2012 It's almost certainly bad code anyway. The free function version of opEq...
- Andrei Alexandrescu (5/21) Jul 12 2012 I agree not a lot of people use obj1 == obj2 instead of
- Andrei Alexandrescu (3/5) Jul 12 2012 Um, I got those swapped. Sorry.
- Steven Schveighoffer (10/22) Jul 12 2012 (fixed above for you)
- Jonathan M Davis (14/39) Jul 12 2012 That raises an interesting point. With these changes, what should opEqua...
- Steven Schveighoffer (10/15) Jul 12 2012 Nope, it could be:
- Mehrdad (2/4) Jul 12 2012 How about inout?
- Steven Schveighoffer (3/7) Jul 12 2012 No. opEquals returns bool.
- Mehrdad (4/14) Jul 12 2012 I meant more like
- Steven Schveighoffer (7/22) Jul 13 2012 inout is meant to transfer the constancy of a parameter to the constancy...
- Jacob Carlborg (4/17) Jul 12 2012 I was trying to suggest something that is mostly backwards compatible.
- Steven Schveighoffer (5/25) Jul 13 2012 I understand. I don't think it's worth it. I'd rather opt-in to the ol...
- Don Clugston (5/44) Jul 12 2012 Well:
- Paulo Pinto (6/91) Jul 12 2012 I don't find them that weird, because many OO languages do have
- Don Clugston (7/67) Jul 12 2012 Really? I find that incredible. Ordered comparisons <, > don't even make...
- Paulo Pinto (10/109) Jul 12 2012 Silly me. I forgot that in D opCmp is more than just equality.
- bearophile (13/14) Jul 12 2012 It's an interesting proposal, and I like it in general.
- Paulo Pinto (8/24) Jul 12 2012 Specially because not all breaking changes are possible, otherwise one
- deadalnix (6/19) Jul 12 2012 I'm thinking fo it for a while. This would be great to have a corpus of
- bearophile (20/25) Jul 12 2012 There is no proof that template bloat won't be a problem in D (I
- Tobias Pankrath (3/8) Jul 12 2012 Why not drop that requirement? What is the use case of different
- bearophile (8/11) Jul 12 2012 It's a requirement that comes from C specs, and I don't know why
- Jacob Carlborg (5/10) Jul 12 2012 But C doesn't have templates, is there some other case where this
- deadalnix (4/12) Jul 12 2012 Nothing prevent the linker to link directly to the new function if the
- Daniel Murphy (5/9) Jul 12 2012 This should be in the linker, not the backend. Keeping function pointer...
- bearophile (6/7) Jul 12 2012 What's important is that all D compilers implement this
- Jacob Carlborg (7/11) Jul 12 2012 Yeah, that was insane. 60 MB for a hello world application is not pretty...
- bearophile (8/13) Jul 12 2012 I'd like to know how much MB are saved using the @templated()
- Michel Fortin (19/31) Jul 12 2012 There's no use for @templated() in the bridge. Classes wrappers and
- Steven Schveighoffer (11/18) Jul 12 2012 Out of curiosity, do you see this becoming a possible improvement on D i...
- Michel Fortin (10/32) Jul 12 2012 Tail const is a orthogonal issue.
- Jacob Carlborg (4/6) Jul 12 2012 It would be so, so nice to have this finished and merged upstream.
- Michel Fortin (25/52) Jul 12 2012 I don't think templates were the culprit for the D/Objective-C bridge.
- deadalnix (4/51) Jul 12 2012 I think this is not a problem as big as it is stated.
- Roman D. Boiko (2/6) Jul 12 2012 L1 cache size is.
- Andrei Alexandrescu (3/9) Jul 12 2012 That must be why he mentioned that most of that code won't be executed.
- deadalnix (2/12) Jul 12 2012 Exactly.
- Steven Schveighoffer (4/12) Jul 12 2012 You will never ever ever convince me that 60MB for a hello world program...
- deadalnix (3/17) Jul 12 2012 It depend what the function look like. if it is 60Mb + x where x is
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (7/30) Jul 12 2012 I don't think you're going to convince your average Android/iOS user to
-
Steven Schveighoffer
(25/53)
Jul 12 2012
On Thu, 12 Jul 2012 12:46:29 -0400, Alex R=C3=B8nne Petersen
- Michel Fortin (12/16) Jul 12 2012 60Mb was only with bindings to the most fundamentals parts of Cocoa. It
- deadalnix (2/7) Jul 12 2012 That is IMO the way to go instead of cluttering the language.
- bearophile (5/6) Jul 12 2012 I think several solutions applied at the same time are needed if
- deadalnix (2/8) Jul 12 2012 The @templated is redundant with that backend capability of LDC.
- bearophile (9/10) Jul 12 2012 The semantics is not the same. This code doesn't compile, the
- Roman D. Boiko (8/13) Jul 12 2012 I agree, they are not needed.
- RivenTheMage (3/11) Jul 12 2012 This has been discussed multiple times on the D forum, I believe.
- Roman D. Boiko (3/16) Jul 12 2012 Do you mean Monitor or all other issues from that post as well?
- Roman D. Boiko (3/24) Jul 12 2012 OK, I found one myself from this post:
- RivenTheMage (2/4) Jul 12 2012 Beat me :)
- RivenTheMage (4/18) Jul 12 2012 Monitor issue.
- Steven Schveighoffer (21/46) Jul 12 2012 yes, this is why we have the weird situation of object.opEquals. I'd li...
- H. S. Teoh (14/26) Jul 12 2012 [...]
- Steven Schveighoffer (7/30) Jul 12 2012 Hm... chicken vs. egg again...
- H. S. Teoh (10/34) Jul 12 2012 [...]
- David Nadlinger (2/6) Jul 12 2012 *cough* … DMD … *cough*.
- Iain Buclaw (5/11) Jul 12 2012 *cough* ... GDC ... *cough*
- Mehrdad (2/3) Jul 12 2012 ... but when I do... :)
- Jonathan M Davis (9/12) Jul 12 2012 True, but it does happen all too often around here (e.g. Andrei with
- deadalnix (3/42) Jul 12 2012 I also had a tilt on that message. This is after reflexion definitively
- kenji hara (19/56) Jul 12 2012 Is this really need?
- bearophile (13/16) Jul 12 2012 I am not expert on English language, but you are one of my
- deadalnix (3/20) Jul 12 2012 mutable and const overload of the same function is a bit weird. I'm not
- Andrei Alexandrescu (5/22) Jul 12 2012 Thanks for being so helpful and flexible! Let's discuss matters a little...
- Jacob Carlborg (4/22) Jul 12 2012 I would have thought that that already worked.
- Jonathan M Davis (4/36) Jul 12 2012 The recently added attribute inferrence for overridden functions in deri...
- Jacob Carlborg (5/7) Jul 12 2012 I wonder if the attribute inference can be fined tuned a bit. So it's
- Jonathan M Davis (5/13) Jul 13 2012 I believe that Kenji has a pull request intended to resolve the issue
- Jacob Carlborg (5/8) Jul 13 2012 This one: https://github.com/D-Programming-Language/dmd/pull/1042 ?
- Jonathan M Davis (4/11) Jul 13 2012 Probably. I'd have to go dig for the associated bug report to be 100% su...
- H. S. Teoh (14/20) Jul 12 2012 [...]
- David Piepgrass (34/40) Jul 12 2012 Well, I'm not convinced it is a good idea to eliminate the stuff
- Andrei Alexandrescu (18/41) Jul 12 2012 The thing is, that can be done in an opt-in manner. People who want
- deadalnix (2/5) Jul 12 2012 This is orthogonal to what we are dealing here.
- David Piepgrass (37/56) Jul 12 2012 But is the constrained environment we're talking about really all
- David Piepgrass (1/2) Jul 12 2012 Oops, I meant IComparable
- Jonathan M Davis (10/12) Jul 12 2012 That will _never_ happen. That completely destroys a number of the benef...
- deadalnix (8/20) Jul 12 2012 This has been discussed and isn't as dumb as you may think. What is
- H. S. Teoh (19/36) Jul 12 2012 Having a class RawObject as a superclass of Object is an equally good
- Andrei Alexandrescu (7/19) Jul 12 2012 As far as backward compatibility goes, I'm not sure. There's code out
- Jacob Carlborg (4/12) Jul 12 2012 Exactly, this is also what Ruby 1.9 does.
- Roman D. Boiko (7/49) Jul 12 2012 +1
- F i L (2/2) Jul 13 2012 I always wondered why toString() wasn't just to!string() in the
- Jonathan M Davis (9/11) Jul 13 2012 to!string(obj) uses typeof(obj).toString for user-defined types. Even if...
- Don Clugston (2/4) Jul 13 2012 toString() comes from the days before D had templates.
- Steven Schveighoffer (9/11) Jul 13 2012 toString in itself is wasteful. It allocates a string that will likely ...
- Peter Alexander (21/28) Jul 13 2012 What C++ community are you in touch with? Boost?...
- Jacob Carlborg (6/8) Jul 13 2012 If I recall correctly, that was due to using too many global variables
Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? Andrei
Jul 11 2012
On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuXReferenced post (for context):its purity, safety, and throwability (although the last two can be worked arround easily). I think we're looking at the wrong problem here. If we're trying to escape problems with 'const' Objects by removing the members form Object entirely, that should be raising a red flag with const, not with Object.The problem is not only in the constness of the argument, but also in
Jul 11 2012
"Mehrdad" , dans le message (digitalmars.D:172012), a écrit :On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu wrote:const has no problem. It is bitwise const, and it works like that. Logical const is not implemented in D, but that is a separate issue. The problem is to force people to use const, because bitwise const may not be suited for their problems. If opEquals and friends are const, then D forces people to use bitwise const, and that is the problem, that is largely widened by the fact that bitwise transitive const is particularly viral. But if we do not impose to implement any const methods, the problem disappear.Required reading prior to this: http://goo.gl/eXpuXReferenced post (for context):its purity, safety, and throwability (although the last two can be worked arround easily). I think we're looking at the wrong problem here. If we're trying to escape problems with 'const' Objects by removing the members form Object entirely, that should be raising a red flag with const, not with Object.The problem is not only in the constness of the argument, but also in
Jul 12 2012
I say: finally. I've long felt that Object was already too heavy, but hadn't worried about it much in years (since there was no apparent solution at that time). Just as notifyRegister/notifyUnRegister were eventually moved out to the runtime, it should be possible to do the same for these, if we cannot just obviate them outright.
Jul 11 2012
On 07/12/2012 06:15 AM, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point.+1.We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiThank you for taking the time. Removing the default methods completely is actually a lot better than making inheriting from Object optional or tweaking const beyond recognition and/or usefulness. I was afraid to suggest this because it breaks all code that assumes that the methods are present in object (most code?), but I think it is a great way to go forward. Regarding toString, getting rid of it would imply that the default way of creating a textual representation of an object would no longer be part of Object, paving the way for the proposal that uses buffers and scope delegates - this will be purely a library thing. Regarding backwards-compatibility, an issue that is trivial to fix is the invalidation of 'override' declarations in the child classes. They can be allowed with the -d switch for those methods. And if they use 'super', the compiler could magically provide the current default implementations.
Jul 11 2012
Timon Gehr , dans le message (digitalmars.D:172014), a écrit :Thank you for taking the time. Removing the default methods completely is actually a lot better than making inheriting from Object optional or tweaking const beyond recognition and/or usefulness. I was afraid to suggest this because it breaks all code that assumes that the methods are present in object (most code?), but I think it is a great way to go forward.It's not worse thant breaking all code that overrides opEqual by changing it's signature.Regarding toString, getting rid of it would imply that the default way of creating a textual representation of an object would no longer be part of Object, paving the way for the proposal that uses buffers and scope delegates - this will be purely a library thing.I agree. toString should be a purely library solution. The standard library could easily use templates trying to use different ways to print the the object, depending on what methods are implemented for that object: direct conversion to string/wstring/dstring, a standard method using delegates, etc.Regarding backwards-compatibility, an issue that is trivial to fix is the invalidation of 'override' declarations in the child classes. They can be allowed with the -d switch for those methods. And if they use 'super', the compiler could magically provide the current default implementations.Magic is not good for langage consistency. I would rather do a different fix: Introduce a class in the standard library that is like the current Object. To correct broken code, make all classes inheriting from Objet inherit from this new class, and rewrite opEqual/opCmp to take this new class as an argument instead of Object. This can be done automatically. People may not want to use that fix, but in that case, we don't have to implement a magical behavior with super. What can be used is deprecation: if I someone uses super.opEqual (meaning Object.opEqual), and others, he should bet a warning saying it's deprectated, with explanations on how to solve the issue. A possible course of action is this: - revert changes in Object (with renewed apologies to people having worked on that) - introduce a class implementing basic Hashes functions with the current signatures. (A class with the new signatures could be provided too, making use of the late work on Object, which would not be completely wasted after all) - introduce a deprecation warning on uses of Object.opEqual and friends, informing the programmer about the possibility to derive from the new class to solve the issue. - in the mean time, make the necessary changes to enable classes not to have those methods (like structs) - after the deprecation period, remove Object.opEqual and friends.
Jul 12 2012
On Thursday, July 12, 2012 00:15:48 Andrei Alexandrescu wrote:What say you?If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed. For the most part, I think that operating on Objects like that is horrible, and we certainly don't encourage it, but it's been possible for ages, so I'm willing to bet that there's plenty of code which does it. For instance, what's Tango do? As I understand it, they're fairly Java-esque in their general approach to things, so it wouldn't entirely surprise me if their containers held Object rather than being templated (though the need to hold primitive types may have made it so that they didn't go that route). I don't know whether that inability to do anything with Object beyond hold it - no comparison, no nothing - is really acceptable or not. It wouldn't mess up anything _I_ do, because I abhor operating on Object - it throws away too much type information and encourages bad practices (such as having a container full of unrelated types which happen to have the same base class) - but plenty of other people do it, and it won't be possible anymore. 2. Will this work with toString? How much stuff relies on being able to get a string from Object? We've been switching everything in Phobos over to use variadic templates, which should make it easy enough to get around that problem (presumably, classes are then in the same boat as structs which don't define toString), but we may have older functions which will run into problems with this, and some stuff in other libraries could be completely screwed by this. Again, what does Tango do? Does it use variadic templates for its print function, or does it use D style variadics? At first glance, it seems to me that getting rid of toString on Object would screw over its use with D style variadics. That may or not be true, but if it is, we're closing doors on stuff which currently works. So, I think that it's probably a solid way to go, and it does appear to solve the const issues that we've been having quite nicely, but it also appears to break a number of things which have worked for some time, and we're going to have to figure out how we're going to deal with that, even if it's only providing a good deprecation path. - Jonathan M Davis P.S. I think that we should still keep how the free function opEquals currently works with regards to comparing Objects of differing types. The comparison won't work with Object anymore, but classes which have opEquals will still have polymorphic opEquals, and I think that all of that great logic that we thought up to solve some of the problems that Java has with that should be kept. So, if anyone was thinking that that only existed because Object has opEquals on it and that it would be unnecessary now, I completely disagree.
Jul 12 2012
On Thursday, 12 July 2012 at 08:40:25 UTC, Jonathan M Davis wrote:it does appear to solve the const issues that we've been having quite nicelyHow would we expect people to deal with these const issues when the issues come up in their own libraries? Or do we not care?
Jul 12 2012
On Thursday, July 12, 2012 11:07:42 Mehrdad wrote:On Thursday, 12 July 2012 at 08:40:25 UTC, Jonathan M Davis wrote:The issue that we're trying to solve here is making opEquals, opCmp, toHash, and toString work both for const and non-const objects. That's it. We're not talking about revamping const. It doesn't need it. I know that you're unhappy with how const works in D, but as a group, we do not believe that it is fundamentally broken. Rather, this particular situation where OO and const collide needs a solution. _That_ is what we're trying to solve. That may mean that you can't use const in your code, because what you're trying to doesn't work with D's const. But taking care of this issue with opEquals, opCmp, toHash, and toString will make avoiding const easier for those that need to for their particular code base. - Jonathan M Davisit does appear to solve the const issues that we've been having quite nicelyHow would we expect people to deal with these const issues when the issues come up in their own libraries? Or do we not care?
Jul 12 2012
On Thursday, 12 July 2012 at 09:32:00 UTC, Jonathan M Davis wrote:The issue that we're trying to solve here is making opEquals,opCmp, toHash, and toString work both for const and non-const objects. That's it. We're not talking about revamping const. It doesn't need it.Depends on what you mean by 'need' I guess? You can either get rid of the cause or the effect, and either way that will get rid of the effect.this particular situation where OO and const collide needs a solution. ... That may mean that you can't use const in your code,Right, I'm not. I'm not complaining about my code here. My point is, there is _nothing_ about this problem that screams out "druntime" or "Phobos" to me. It's a problem that can happen to _anyone_ using trying to use 'const' with base classes in OOP. So if you're saying you can't use const with OOP, then I'm saying one of those needs to be fixed, and I was suggesting the former as a candidate. But if you're saying this problem is somehow 'special' in some way, then would you please mention how?
Jul 12 2012
On Thu, 12 Jul 2012 11:47:10 -0400, Mehrdad <wfunction hotmail.com> wrote:But if you're saying this problem is somehow 'special' in some way, then would you please mention how?Because you have no choice what your base class is -- Object. And if Object uses const, so must you. -Steve
Jul 12 2012
On Thursday, July 12, 2012 17:47:10 Mehrdad wrote:So if you're saying you can't use const with OOP, then I'm saying one of those needs to be fixed, and I was suggesting the former as a candidate.You can use const and OOP together just fine, but that means that if you have a function which is marked as const in the base class, and you're operating on the objects through the base class pointer, then all of the derived classes must be able to have that function as const. In general, I really don' think that that's a big deal. The problem is that opEquals, opCmp, toHash, and toString affect _all_ classes, because they're in Object, and that unnecessarily restricts all classes. const is forced on you, and it's forced on you with incredibly common functions in a way that completely disallows some idioms (e.g. caching and lazy loading). On the other hand, if you're dealing with your own class hierarchy, you can choose what you're going to mark as const or not, and so you can either forgoe const entirely or only use it on functions where you can reasonably require that they be const in all classes in that hierarchy. It's not being forced on you, and you can pick what works best for your set of classes. The fact that const is restrictive isn't the problem. It's the fact that const is forced on you which is. As long as you have the choice whether to use it or not, then it's fine. - Jonathan M Davis
Jul 12 2012
On Thursday, 12 July 2012 at 19:38:03 UTC, Jonathan M Davis wrote:On the other hand, if you're dealing with your own class hierarchy, you can choose what you're going to mark as const or notSay person X who develops a class A with a const member similar to opEquals or whatever suits your fancy. Say person Y is using person X's library (person X doesn't even _know_ person Y, let alone show him the source code), and finds that too restricting. It's being "forced onto them". Could you tell me how this situation is different from the above? How is person Y supposed to solve this problem? Modify the declarations? cast()?
Jul 12 2012
On 07/13/2012 10:04 AM, Mehrdad wrote:On Thursday, 12 July 2012 at 19:38:03 UTC, Jonathan M Davis wrote:Again, it's a matter of choice. You can always choose to use a particular library, alternative, or implement your own solution. How to you choose *not* to derive your classes from Object?On the other hand, if you're dealing with your own class hierarchy, you can choose what you're going to mark as const or notSay person X who develops a class A with a const member similar to opEquals or whatever suits your fancy. Say person Y is using person X's library (person X doesn't even _know_ person Y, let alone show him the source code), and finds that too restricting. It's being "forced onto them". Could you tell me how this situation is different from the above? How is person Y supposed to solve this problem? Modify the declarations? cast()?
Jul 12 2012
On Friday, 13 July 2012 at 01:10:16 UTC, Mike Parker wrote:Again, it's a matter of choice. You can always choose to use a particular library, alternative, or implement your own solution. How to you choose *not* to derive your classes from Object?You mean, "how do you choose *not* to use opEquals()?"?
Jul 12 2012
On Friday, July 13, 2012 03:15:41 Mehrdad wrote:On Friday, 13 July 2012 at 01:10:16 UTC, Mike Parker wrote:Yes. Restrictions placed on Object affect _everyone_ using the language, whereas restrictions placed on a particular library only affect the users of that library. So, Object needs to be able to work without forcing const on anyone using it, whereas a 3rd library doesn't necessarily need to. - Jonathan M DavisAgain, it's a matter of choice. You can always choose to use a particular library, alternative, or implement your own solution. How to you choose *not* to derive your classes from Object?You mean, "how do you choose *not* to use opEquals()?"?
Jul 12 2012
On Friday, 13 July 2012 at 01:10:16 UTC, Mike Parker wrote:Again, it's a matter of choice. You can always choose to use a particular library, alternative, or implement your own solution. How to you choose *not* to derive your classes from Object?You mean, "how do you choose *not* to use opEquals()?"?
Jul 12 2012
On Friday, July 13, 2012 10:10:14 Mike Parker wrote:On 07/13/2012 10:04 AM, Mehrdad wrote:Exactly. const, safe, pure, nothrow, etc. all provide benefits and guarantees, but they also place certain restrictions on your code. In most cases, those restrictions are just fine, so there's great benefit in using them. In rarer cases, those restrictions are too much (e.g. you must have lazy loading in your object or you need to be able to have equality based on database queries), in which case you just avoid the attributes that are incompatible with the idiom or approach that you're using. If a 3rd party library works with what you're trying to do and fulfill your needs, then you may use it. If it doesn't work with what you're trying to do, then you don't. It can be annoying if you'd really like to use a particular library and can't because of its design decisions, but that can happen completely separately from const, pure, etc. But with a 3rd party library, you generally have options - there are always other libraries, whereas with the language itself, if it has a particular restriction disallows what you're trying to do, then you're going to have to not use that language. There's big difference between a library and a the language itself. - Jonathan M DavisOn Thursday, 12 July 2012 at 19:38:03 UTC, Jonathan M Davis wrote:Again, it's a matter of choice. You can always choose to use a particular library, alternative, or implement your own solution. How to you choose *not* to derive your classes from Object?On the other hand, if you're dealing with your own class hierarchy, you can choose what you're going to mark as const or notSay person X who develops a class A with a const member similar to opEquals or whatever suits your fancy. Say person Y is using person X's library (person X doesn't even _know_ person Y, let alone show him the source code), and finds that too restricting. It's being "forced onto them". Could you tell me how this situation is different from the above? How is person Y supposed to solve this problem? Modify the declarations? cast()?
Jul 12 2012
On Friday, 13 July 2012 at 01:22:59 UTC, Jonathan M Davis wrote:There's big difference between a library and a the language itself.Surely that's a non sequitur... Aren't we modifying druntime here? What part of this has to do with the _language_? Isn't druntime a library? Also, why can't you tell the user, "it's open-source! If it doesn't suit your needs, go modify it! Removing const is trivial!" What makes it so easy to say that about every library /except/ druntime?You mean, "how do you choose *not* to use opEquals()?"?Yes. Restrictions placed on Object affect _everyone_ using the language, whereas restrictions placed on a particular library only affect the users of that library. So, Object needs to be able to work without forcing const on anyone using it, whereas a 3rd library doesn't necessarily need to.1. Again, see above -- Object is also in a library. Why doesn't the reasoning apply there? It's trivial to remove const from the library and recompile it -- _FAR_ easier than it is to modify any arbitrary library. (Speaking of which, thanks for making it so easy to modify & recompile druntime!) 2. Isn't it kinda /trivial/ to avoid opEquals? Just don't use it. Make up your own method. What's wrong with this?
Jul 12 2012
On Thu, 12 Jul 2012 21:30:36 -0400, Mehrdad <wfunction hotmail.com> wrote:On Friday, 13 July 2012 at 01:22:59 UTC, Jonathan M Davis wrote:First, Object (and the functions in object_.d) is treated specially by the compiler. For exammple, object.opEquals worked on const objects, even though the function parameters were not const. Second, If you change druntime, you might as well be hacking the compiler. Every *single* library depends on druntime, including phobos. Are you going to change all them too? It's like saying it's as easy to prune a tree trunk as it is to prune a branch.There's big difference between a library and a the language itself.Surely that's a non sequitur... Aren't we modifying druntime here? What part of this has to do with the _language_? Isn't druntime a library? Also, why can't you tell the user, "it's open-source! If it doesn't suit your needs, go modify it! Removing const is trivial!" What makes it so easy to say that about every library /except/ druntime?1. Again, see above -- Object is also in a library. Why doesn't the reasoning apply there? It's trivial to remove const from the library and recompile it -- _FAR_ easier than it is to modify any arbitrary library. (Speaking of which, thanks for making it so easy to modify & recompile druntime!)No, it's not. Everything depends on druntime. If you think it was so easy, look at the date of this bug report, which all the top dogs agreed with: http://d.puremagic.com/issues/show_bug.cgi?id=18242. Isn't it kinda /trivial/ to avoid opEquals? Just don't use it. Make up your own method. What's wrong with this?Yes, it is. There isn't anything wrong with that, and it has been suggested -- if you want non-const opEquals, write your own method. But I think we are past that point, in all likelihood, opEquals is going away from Object. -Steve
Jul 12 2012
On Friday, 13 July 2012 at 02:11:02 UTC, Steven Schveighoffer wrote:No, it's not. Everything depends on druntime. If you think it was so easy, look at the date of this bug report, which all the top dogs agreed with: http://d.puremagic.com/issues/show_bug.cgi?id=1824Thanks for providing the link, I'll take a look at it. I'd never known opEquals was treated specially by the compiler (aside from operator overloading of course), that would change a lot of things.Well I'm not understanding the point of this post then... though thanks for letting me know I guess.2. Isn't it kinda /trivial/ to avoid opEquals? Just don't use it. Make up your own method. What's wrong with this?Yes, it is. There isn't anything wrong with that, and it has been suggested -- if you want non-const opEquals, write your own method. But I think we are past that point, in all likelihood, opEquals is going away from Object.
Jul 12 2012
On Friday, July 13, 2012 03:30:36 Mehrdad wrote:On Friday, 13 July 2012 at 01:22:59 UTC, Jonathan M Davis wrote:druntime is the runtime for D. The compiler uses it to implement key aspects of the language (e.g. new). Without it, you don't have D. It's effectively part of the language. Yes, you can replace it with your own version if you want to, but if you do so, you're essentially make your own variant of the language.There's big difference between a library and a the language itself.Surely that's a non sequitur... Aren't we modifying druntime here? What part of this has to do with the _language_? Isn't druntime a library?2. Isn't it kinda /trivial/ to avoid opEquals? Just don't use it. Make up your own method. What's wrong with this?Stuff like AAs rely on it. So yes, if opEquals, opCmp, toHash, and toString were all const, classes could just override them, put assert(0); as their bodies, and not use them, but then anything requiring those functions - including the built AAs and standard library stuff such as format and writeln - would not only not work right, but they would kill your program when they were used. == itself used on such an object would kill your program. So, as it stands, whole language features become impossible to use with classes which can't be implemented with those 4 functions being const. You could only use classes which can't be const by avoiding those language features completely. The proposed changes would make it possible for all of those features to be used by programs which didn't use const. - Jonathan M Davis
Jul 12 2012
On 7/12/2012 12:59 AM, Jonathan M Davis wrote:So, I think that it's probably a solid way to go, and it does appear to solve the const issues that we've been having quite nicely, but it also appears to break a number of things which have worked for some time, and we're going to have to figure out how we're going to deal with that, even if it's only providing a good deprecation path.A main motivation for going this route is to avoid breaking existing code.
Jul 12 2012
On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:On 7/12/2012 12:59 AM, Jonathan M Davis wrote:Except that it's _guaranteed_ to break code, because anything which relies on Object having opEquals, opCmp, toHash, or toString is going to break. We can provide an appropriate deprecation path to ease the transition, but this _will_ break code. - Jonathan M DavisSo, I think that it's probably a solid way to go, and it does appear to solve the const issues that we've been having quite nicely, but it also appears to break a number of things which have worked for some time, and we're going to have to figure out how we're going to deal with that, even if it's only providing a good deprecation path.A main motivation for going this route is to avoid breaking existing code.
Jul 12 2012
On 12/07/2012 11:51, Jonathan M Davis wrote:On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:I'd advocate that rely on Object isn't a wise idea anyway. I've worked quite a lot in java and it is a recurring problem (mostly because of the way generic is implemented). The problem we encountered here are another confirmation of that. We have much greater metaprogramming capabilities than Java, and it seems like a good idea to leverage that.On 7/12/2012 12:59 AM, Jonathan M Davis wrote:Except that it's _guaranteed_ to break code, because anything which relies on Object having opEquals, opCmp, toHash, or toString is going to break. We can provide an appropriate deprecation path to ease the transition, but this _will_ break code. - Jonathan M DavisSo, I think that it's probably a solid way to go, and it does appear to solve the const issues that we've been having quite nicely, but it also appears to break a number of things which have worked for some time, and we're going to have to figure out how we're going to deal with that, even if it's only providing a good deprecation path.A main motivation for going this route is to avoid breaking existing code.
Jul 12 2012
On 7/12/2012 2:51 AM, Jonathan M Davis wrote:On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:Which is why we'll be leaving those members in Object for the foreseeable future.A main motivation for going this route is to avoid breaking existing code.Except that it's _guaranteed_ to break code, because anything which relies on Object having opEquals, opCmp, toHash, or toString is going to break. We can provide an appropriate deprecation path to ease the transition, but this _will_ break code.
Jul 12 2012
On 2012-07-12 09:59, Jonathan M Davis wrote:For the most part, I think that operating on Objects like that is horrible, and we certainly don't encourage it, but it's been possible for ages, so I'm willing to bet that there's plenty of code which does it. For instance, what's Tango do? As I understand it, they're fairly Java-esque in their general approach to things, so it wouldn't entirely surprise me if their containers held Object rather than being templated (though the need to hold primitive types may have made it so that they didn't go that route).All containers in Tango are templated classes, interfaces or structs. Just because Tango have more of a class hierarchy and nested packages than Phobos doesn't mean it doesn't use templates.2. Will this work with toString? How much stuff relies on being able to get a string from Object? We've been switching everything in Phobos over to use variadic templates, which should make it easy enough to get around that problem (presumably, classes are then in the same boat as structs which don't define toString), but we may have older functions which will run into problems with this, and some stuff in other libraries could be completely screwed by this. Again, what does Tango do? Does it use variadic templates for its print function, or does it use D style variadics? At first glance, it seems to me that getting rid of toString on Object would screw over its use with D style variadics. That may or not be true, but if it is, we're closing doors on stuff which currently works.Tango uses D style variadics for printing. -- /Jacob Carlborg
Jul 12 2012
On 7/12/12 3:59 AM, Jonathan M Davis wrote:If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way. Andrei
Jul 12 2012
On Thursday, 12 July 2012 at 13:20:47 UTC, Andrei Alexandrescu wrote:On 7/12/12 3:59 AM, Jonathan M Davis wrote:+1If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way. Andrei
Jul 12 2012
On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 7/12/12 3:59 AM, Jonathan M Davis wrote:Hm... I don't like this, it slows down a very basic function. I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject). -SteveIf you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.
Jul 12 2012
On Thursday, 12 July 2012 at 13:39:54 UTC, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.Hm... I don't like this, it slows down a very basic function. I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject). -Steve
Jul 12 2012
On Thursday, 12 July 2012 at 13:41:52 UTC, Roman D. Boiko wrote: ... ups. I meant +1.
Jul 12 2012
On 7/12/12 9:39 AM, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It's one comparison.On 7/12/12 3:59 AM, Jonathan M Davis wrote:Hm... I don't like this, it slows down a very basic function.If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject).Too complicated. I think we can afford one comparison. Andrei
Jul 12 2012
Andrei Alexandrescu:Too complicated. I think we can afford one comparison.An annotation for old style classes? Bye, bearophile
Jul 12 2012
On Thursday, 12 July 2012 at 13:49:29 UTC, Andrei Alexandrescu wrote:Too complicated. I think we can afford one comparison.One comparison for each of these basic usages. Would branch prediction work fine in each use case? Anyway I vote for removing those methods from the root class.
Jul 12 2012
On 12/07/2012 15:49, Andrei Alexandrescu wrote:On 7/12/12 9:39 AM, Steven Schveighoffer wrote:And one branching. In itself it isn't high cost, but can become a problem in a tight loop, say a sort function for instance.On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It's one comparison.On 7/12/12 3:59 AM, Jonathan M Davis wrote:Hm... I don't like this, it slows down a very basic function.If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.
Jul 12 2012
On 7/12/12 10:40 AM, deadalnix wrote:And one branching. In itself it isn't high cost, but can become a problem in a tight loop, say a sort function for instance.Cost should be assessed in comparison to the baseline work that is being performed. At any rate, the branch predictor should take care of branches that mostly go one way in a loop. Andrei
Jul 12 2012
On Thu, 12 Jul 2012 09:49:29 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 7/12/12 9:39 AM, Steven Schveighoffer wrote:I don't know if it's one comparison, and really, we are doubling the vtable lookups. I think the compiler should be able to optimize to one vtable lookup. Aside from this, the baggage of four dead functions in every vtable is pretty hefty, is there a path to deprecation, or are the four horseman of the const apocalypse going to exist forever? It would suck to have to deal with these issues forever. -SteveOn Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It's one comparison.On 7/12/12 3:59 AM, Jonathan M Davis wrote:Hm... I don't like this, it slows down a very basic function.If you can figure out how to make this work, it's fine by me. However, I see two potential issuses which cause currently working idioms to no longer work: 1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.I've been thinking more about this and it's possible to keep good backwards compatibility by "marginalizing" instead of eliminating the four culprits. Consider: class A { void fun() {} } class B : A { void fun() {} } class C : A {} void main() { A objA = new A; A objB = new B; A objC = new C; assert((&objA.fun).funcptr != (&objB.fun).funcptr); assert((&objA.fun).funcptr == (&objC.fun).funcptr); } In brief there _is_ a way to check during runtime whether a class has overridden a method. If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject).Too complicated. I think we can afford one comparison.
Jul 12 2012
On 7/12/12 12:05 PM, Steven Schveighoffer wrote:Aside from this, the baggage of four dead functions in every vtable is pretty hefty, is there a path to deprecation, or are the four horseman of the const apocalypse going to exist forever? It would suck to have to deal with these issues forever.I think we'll find ways to deprecate them later. Andrei
Jul 12 2012
On 2012-07-12 15:39, Steven Schveighoffer wrote:I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject).Wouldn't the default be to inherit from Object? Like this: class RawObject {} class Object : RawObject {} class Foo {} // inherits from Object by default. Most people would not need to change anything, they can continue to use Object. If they want to avoid the methods declared in Object they need to explicitly inherit from RawObject. -- /Jacob Carlborg
Jul 12 2012
On Thu, 12 Jul 2012 14:43:57 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-07-12 15:39, Steven Schveighoffer wrote:Many (most?) classes never care about opHash, opCmp, opEquals and toString. But Object defines them, incorrectly for most cases. These apathetic classes would not break at all. And to make the default be to inherit those methods would promote their usage or reliance on them. Not only that, but you are almost *forced* to define them, because you don't want accidental incorrect usage of them. We have lovely situations where the only solution is to define a version of the method that *always throws* in a statically typed language. It's really a terrible solution (to force the definition of them) which Andrei quite correctly pointed out only existed because of the lack of templates back then. I think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes. -SteveI think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions. It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject).Wouldn't the default be to inherit from Object? Like this: class RawObject {} class Object : RawObject {} class Foo {} // inherits from Object by default. Most people would not need to change anything, they can continue to use Object. If they want to avoid the methods declared in Object they need to explicitly inherit from RawObject.
Jul 12 2012
On 7/12/12 4:20 PM, Steven Schveighoffer wrote:I think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes.Well I wasn't keen on eliminating the four methods and look what happened! Andrei
Jul 12 2012
On Thu, 12 Jul 2012 16:27:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 7/12/12 4:20 PM, Steven Schveighoffer wrote:My personal opinion is we should simply eliminate the four methods (or at least the three required for AAs), fix AAs, and deal with the fallout. I can't really remember the last time I simply used obj1.opEquals(obj2) to do comparisons instead of obj1 == obj2 (which should do the right thing if obj1.opEquals(obj2) is valid). The code that relies on this is probably very rare. I certainly would *love* to rewrite all my opCmp and opEquals functions to accept the minimal base class instead of doing the dual dispatch dance with Object parameters. I'm also actually not liking using Object as the scorned child of RawObject, I'd rather keep Object as the base, and use something like OldObject as a different base class, or maybe use an interface. I still am not keen on having a runtime vtable comparison to see if we want to mimic old behavior, how does one declare "this comparison isn't valid" to the compiler? That is one of the main benefits I see with dumping the methods. -SteveI think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes.Well I wasn't keen on eliminating the four methods and look what happened!
Jul 12 2012
On Thursday, July 12, 2012 16:50:21 Steven Schveighoffer wrote:I can't really remember the last time I simply used obj1.opEquals(obj2) to do comparisons instead of obj1 == obj2 (which should do the right thing if obj1.opEquals(obj2) is valid). The code that relies on this is probably very rare.It's almost certainly bad code anyway. The free function version of opEquals specifically does extra work to make equality checks correct and avoids some of the pitfalls that opEquals causes in Java (e.g. doing comparison in both directions if the types aren't identical). So, if we break that, it's probably a _good_ thing. And if they _really_ want to do that, that can still do it with their derived classes which define opEquals. They just can't do it with Object. - Jonathan M Davis
Jul 12 2012
On 7/12/12 4:50 PM, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 16:27:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I agree not a lot of people use obj1 == obj2 instead of obj1.opEquals(obj2), but I assume quite a few override opEquals and rely on it being called. AndreiOn 7/12/12 4:20 PM, Steven Schveighoffer wrote:My personal opinion is we should simply eliminate the four methods (or at least the three required for AAs), fix AAs, and deal with the fallout. I can't really remember the last time I simply used obj1.opEquals(obj2) to do comparisons instead of obj1 == obj2 (which should do the right thing if obj1.opEquals(obj2) is valid). The code that relies on this is probably very rare. I certainly would *love* to rewrite all my opCmp and opEquals functions to accept the minimal base class instead of doing the dual dispatch dance with Object parameters.I think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes.Well I wasn't keen on eliminating the four methods and look what happened!
Jul 12 2012
On 7/12/12 6:38 PM, Andrei Alexandrescu wrote:I agree not a lot of people use obj1 == obj2 instead of obj1.opEquals(obj2)Um, I got those swapped. Sorry. Andrei
Jul 12 2012
On Thu, 12 Jul 2012 18:38:06 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 7/12/12 4:50 PM, Steven Schveighoffer wrote:(fixed above for you) Yes, and why would that not work? If opEquals is defined as: bool opEquals(Object o) Won't this still be called by the compiler, even if Object does not define it? (assuming the extraneous override keyword is removed) This would be an issue if people stored all their objects as Objects, which is very rare also I think. -SteveMy personal opinion is we should simply eliminate the four methods (or at least the three required for AAs), fix AAs, and deal with the fallout. I can't really remember the last time I simply used obj1.opEquals(obj2) to do comparisons instead of obj1 == obj2 (which should do the right thing if obj1.opEquals(obj2) is valid). The code that relies on this is probably very rare. I certainly would *love* to rewrite all my opCmp and opEquals functions to accept the minimal base class instead of doing the dual dispatch dance with Object parameters.I agree not a lot of people use obj1.opEquals(obj2) instead of obj1 == obj2, but I assume quite a few override opEquals and rely on it being called.
Jul 12 2012
On Thursday, July 12, 2012 22:08:01 Steven Schveighoffer wrote:On Thu, 12 Jul 2012 18:38:06 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That raises an interesting point. With these changes, what should opEquals' signature be for classes? Right now, it's always bool opEquals(Object obj); Would it still have to be that? It wouldn't really make sense for it be, since you couldn't use == on Object. Would it then use the most basic class which uses (i.e. the least derived class) which implements opEquals? Or would each derived class implement it with their type? Doing that causes overload issues, because then you have to alias every base class' overload to be able to use == against every base class' type. Is the solution to then to template opEquals and make it non-virtual? I don't know. D's overload rules could make this a bit interesting. We need to figure out exactly what opEquals' and opCmp's signatures are going to need to look like. - Jonathan M DavisOn 7/12/12 4:50 PM, Steven Schveighoffer wrote:(fixed above for you) Yes, and why would that not work? If opEquals is defined as: bool opEquals(Object o) Won't this still be called by the compiler, even if Object does not define it? (assuming the extraneous override keyword is removed)My personal opinion is we should simply eliminate the four methods (or at least the three required for AAs), fix AAs, and deal with the fallout. I can't really remember the last time I simply used obj1.opEquals(obj2) to do comparisons instead of obj1 == obj2 (which should do the right thing if obj1.opEquals(obj2) is valid). The code that relies on this is probably very rare. I certainly would *love* to rewrite all my opCmp and opEquals functions to accept the minimal base class instead of doing the dual dispatch dance with Object parameters.I agree not a lot of people use obj1.opEquals(obj2) instead of obj1 == obj2, but I assume quite a few override opEquals and rely on it being called.
Jul 12 2012
On Thu, 12 Jul 2012 22:19:35 -0400, Jonathan M Davis <jmdavisProg gmx.com> wrote:That raises an interesting point. With these changes, what should opEquals' signature be for classes? Right now, it's always bool opEquals(Object obj); Would it still have to be that?Nope, it could be: bool opEquals(WhateverYouWant x); It all depends on the situation and the hierarchy. If you are frequently using base classes, you will need to override the base class member. You could duplicate the exact situation we have now in your own hierarchy if you wish. You could add const if you wish. or pure, or safe. With no base defined by the language, you are free to do whatever you want. -Steve
Jul 12 2012
On Friday, 13 July 2012 at 02:19:49 UTC, Jonathan M Davis wrote:That raises an interesting point. With these changes, what should opEquals' signature be for classes?How about inout?
Jul 12 2012
On Thu, 12 Jul 2012 23:51:22 -0400, Mehrdad <wfunction hotmail.com> wrote:On Friday, 13 July 2012 at 02:19:49 UTC, Jonathan M Davis wrote:No. opEquals returns bool. -SteveThat raises an interesting point. With these changes, what should opEquals' signature be for classes?How about inout?
Jul 12 2012
On Friday, 13 July 2012 at 03:57:21 UTC, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 23:51:22 -0400, Mehrdad <wfunction hotmail.com> wrote:I meant more like bool opEquals(inout Object other) inout;On Friday, 13 July 2012 at 02:19:49 UTC, Jonathan M Davis wrote:No. opEquals returns bool. -SteveThat raises an interesting point. With these changes, what should opEquals' signature be for classes?How about inout?
Jul 12 2012
On Fri, 13 Jul 2012 00:18:22 -0400, Mehrdad <wfunction hotmail.com> wrote:On Friday, 13 July 2012 at 03:57:21 UTC, Steven Schveighoffer wrote:inout is meant to transfer the constancy of a parameter to the constancy of the return value. During function execution, inout is treated as another flavor of const (i.e. not modifiable). The above function is basically equivalent to: bool opEquals(const Object other) const; -SteveOn Thu, 12 Jul 2012 23:51:22 -0400, Mehrdad <wfunction hotmail.com> wrote:I meant more like bool opEquals(inout Object other) inout;On Friday, 13 July 2012 at 02:19:49 UTC, Jonathan M Davis wrote:No. opEquals returns bool. -SteveThat raises an interesting point. With these changes, what should opEquals' signature be for classes?How about inout?
Jul 13 2012
On 2012-07-12 22:20, Steven Schveighoffer wrote:Many (most?) classes never care about opHash, opCmp, opEquals and toString. But Object defines them, incorrectly for most cases. These apathetic classes would not break at all. And to make the default be to inherit those methods would promote their usage or reliance on them. Not only that, but you are almost *forced* to define them, because you don't want accidental incorrect usage of them. We have lovely situations where the only solution is to define a version of the method that *always throws* in a statically typed language. It's really a terrible solution (to force the definition of them) which Andrei quite correctly pointed out only existed because of the lack of templates back then. I think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes.I was trying to suggest something that is mostly backwards compatible. -- /Jacob Carlborg
Jul 12 2012
On Fri, 13 Jul 2012 02:49:01 -0400, Jacob Carlborg <doob me.com> wrote:On 2012-07-12 22:20, Steven Schveighoffer wrote:I understand. I don't think it's worth it. I'd rather opt-in to the old way than opt-out. People are lazy, they will likely avoid specifying an alternate base class. -SteveMany (most?) classes never care about opHash, opCmp, opEquals and toString. But Object defines them, incorrectly for most cases. These apathetic classes would not break at all. And to make the default be to inherit those methods would promote their usage or reliance on them. Not only that, but you are almost *forced* to define them, because you don't want accidental incorrect usage of them. We have lovely situations where the only solution is to define a version of the method that *always throws* in a statically typed language. It's really a terrible solution (to force the definition of them) which Andrei quite correctly pointed out only existed because of the lack of templates back then. I think this discussion is somewhat academic at this point, as Andrei seems not too keen on the idea of having dual base classes.I was trying to suggest something that is mostly backwards compatible.
Jul 13 2012
On 12/07/12 06:15, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiWell: * having opCmp() defined for all objects is just plain weird. * toString() is a poor design anyway. But we'd need to be very careful, this is a very disruptive change.
Jul 12 2012
On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:On 12/07/12 06:15, Andrei Alexandrescu wrote:I don't find them that weird, because many OO languages do have them. But I am fine with the design that feels better in D. -- PauloRequired reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiWell: * having opCmp() defined for all objects is just plain weird. * toString() is a poor design anyway. But we'd need to be very careful, this is a very disruptive change.
Jul 12 2012
On 12/07/12 12:00, Paulo Pinto wrote:On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:Really? I find that incredible. Ordered comparisons <, > don't even make sense for many mathematical objects! You can't even define opCmp for a float. Object f = new FtpConnection; Object e = new Employee("Bob"); if (f > e) // Huh???On 12/07/12 06:15, Andrei Alexandrescu wrote:I don't find them that weird, because many OO languages do have them.Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiWell: * having opCmp() defined for all objects is just plain weird. * toString() is a poor design anyway. But we'd need to be very careful, this is a very disruptive change.
Jul 12 2012
On Thursday, 12 July 2012 at 11:03:37 UTC, Don Clugston wrote:On 12/07/12 12:00, Paulo Pinto wrote:Silly me. I forgot that in D opCmp is more than just equality. toString() I find it helpful specially in the cases where objects don't give enough external information. This is usable in scenarios where printf debugging is the only way. Then again, it relies on the developer to have written a sensible toString() to start with. On second thought you're probably right. -- PauloOn Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:Really? I find that incredible. Ordered comparisons <, > don't even make sense for many mathematical objects! You can't even define opCmp for a float. Object f = new FtpConnection; Object e = new Employee("Bob"); if (f > e) // Huh???On 12/07/12 06:15, Andrei Alexandrescu wrote:I don't find them that weird, because many OO languages do have them.Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiWell: * having opCmp() defined for all objects is just plain weird. * toString() is a poor design anyway. But we'd need to be very careful, this is a very disruptive change.
Jul 12 2012
Andrei Alexandrescu:What say you?It's an interesting proposal, and I like it in general. In D the C++-improved template system and the Java-copied OOP are partially a duplication, they sometimes offer two different ways to do similar things. I think this proposal reduces this duplication a bit. This whole discussion comes mostly from fixing an old Bugzilla bug. What other important bugs are open that risk requiring significant changes in D? I suggest to look for such breaking bug fixes asap, instead of waiting 2+ more years to find some bug that requires more important D changes to be fixed :-) Bye, bearophile
Jul 12 2012
"bearophile" wrote in message news:xrbtkoercscroxgtodcu forum.dlang.org...Specially because not all breaking changes are possible, otherwise one has something like Python 3. Which is a very good improvement, but leads to resistance to upgrade. On the other hand, these type of continuous changes lead to FUD about D not being stable and usable for projects. So I guess a kind of balance needs to be achieved. -- PauloAndrei Alexandrescu: What say you?It's an interesting proposal, and I like it in general. In D the C++-improved template system and the Java-copied OOP are partially a duplication, they sometimes offer two different ways to do similar things. I think this proposal reduces this duplication a bit. This whole discussion comes mostly from fixing an old Bugzilla bug. What other important bugs are open that risk requiring significant changes in D? I suggest to look for such breaking bug fixes asap, instead of waiting 2+ more years to find some bug that requires more important D changes to be fixed :-) Bye, bearophile
Jul 12 2012
On 12/07/2012 13:21, bearophile wrote:Andrei Alexandrescu:I'm thinking fo it for a while. This would be great to have a corpus of D code from volunteer project that can be used to test how much breakage does a disruptive change. For this one, I bet not that much, but that is hard to assert without real world data.What say you?It's an interesting proposal, and I like it in general. In D the C++-improved template system and the Java-copied OOP are partially a duplication, they sometimes offer two different ways to do similar things. I think this proposal reduces this duplication a bit. This whole discussion comes mostly from fixing an old Bugzilla bug. What other important bugs are open that risk requiring significant changes in D? I suggest to look for such breaking bug fixes asap, instead of waiting 2+ more years to find some bug that requires more important D changes to be fixed :-) Bye, bearophile
Jul 12 2012
Andrei Alexandrescu:The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.There is no proof that template bloat won't be a problem in D (I remember the first version of the D Objective-C bridge failing because of code bloat, the second version seems to require changes in the D language). And it seems L1 code caches of CPUs aren't growing a lot (so I suggest to not ignore having lot of code to swap in and out of those 32 kbytes). So maybe it will be useful to introduce in D some means to attack the code bloat problem from several sides at the same time. Some time ago I have suggested one of such weapons, the templated() that allows to select what parts of a struct/class are templated regarding to what template arguments (it's a refinement of an idea of Stroustrup). Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct). Bye, bearophile
Jul 12 2012
Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).Why not drop that requirement? What is the use case of different function pointers for different but equivalent functions? Does anyone depend on this?
Jul 12 2012
Tobias Pankrath:Why not drop that requirement? What is the use case of different function pointers for different but equivalent functions? Does anyone depend on this?It's a requirement that comes from C specs, and I don't know why C was designed that way, as usual I am not expert enough. I prefer to not change the semantics of D over C unless there is an important reason, especially when I don't know/understand the rationale of the original C design :-) Bye, bearophile
Jul 12 2012
On 2012-07-12 13:57, bearophile wrote:It's a requirement that comes from C specs, and I don't know why C was designed that way, as usual I am not expert enough. I prefer to not change the semantics of D over C unless there is an important reason, especially when I don't know/understand the rationale of the original C design :-)But C doesn't have templates, is there some other case where this happens as well? -- /Jacob Carlborg
Jul 12 2012
On 12/07/2012 13:50, Tobias Pankrath wrote:Nothing prevent the linker to link directly to the new function if the body is only a branch instruction. This have a cost only when doing indirect call, and the indirect call is greater than a branch instruction.Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).Why not drop that requirement? What is the use case of different function pointers for different but equivalent functions? Does anyone depend on this?
Jul 12 2012
"bearophile" <bearophileHUGS lycos.com> wrote in message news:thmrfdsenkmtasilhocp forum.dlang.org...Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).This should be in the linker, not the backend. Keeping function pointers distinct is probably not that important, using shared libraries/dlls can (supposably) already break them.
Jul 12 2012
Daniel Murphy:This should be in the linker, not the backend.What's important is that all D compilers implement this optimization (or something better, if compatible, like merging pieces of partially equal functions). Bye, bearophile
Jul 12 2012
On 2012-07-12 13:41, bearophile wrote:There is no proof that template bloat won't be a problem in D (I remember the first version of the D Objective-C bridge failing because of code bloat, the second version seems to require changes in the D language).Yeah, that was insane. 60 MB for a hello world application is not pretty. The second version is not a bridge, it changes the language to be ABI compatible with Objective-C. Supports extern(Objective-C) just as extern(C). -- /Jacob Carlborg
Jul 12 2012
Jacob Carlborg:Yeah, that was insane. 60 MB for a hello world application is not pretty.I'd like to know how much MB are saved using the templated() pervasively in that first implementation... :-)The second version is not a bridge, it changes the language to be ABI compatible with Objective-C.<I vaguely remember a language that allows to specify a custom calling convention from the language itself. I don't know if this general feature is worth adding to D. Bye, bearophile
Jul 12 2012
On 2012-07-12 13:01:42 +0000, "bearophile" <bearophileHUGS lycos.com> said:Jacob Carlborg:There's no use for templated() in the bridge. Classes wrappers and function wrappers are not templates, they're mixins. You end up with a lot of non-templated virtual functions in each class.Yeah, that was insane. 60 MB for a hello world application is not pretty.I'd like to know how much MB are saved using the templated() pervasively in that first implementation... :-)But you don't even need a custom calling convention to call Objective-C code in D (hence why the previous approach with the bridge worked!). Objective-C method use the same calling convention as variadic C functions. D/Objective-C (the compiler addition) is much more than that. It's support and cohabitation of a second object ABI, it's support for Objective-C exceptions mixed with D exceptions, support for Objective-C string and selector literals, class objects and overridable class methods, overriding, contracts added to the Objective-C object model, Objective-C protocols (through interfaces), plus a few other things which haven't been implemented at this time. -- Michel Fortin michel.fortin michelf.com http://michelf.com/The second version is not a bridge, it changes the language to be ABI compatible with Objective-C.<I vaguely remember a language that allows to specify a custom calling convention from the language itself. I don't know if this general feature is worth adding to D.
Jul 12 2012
On Thu, 12 Jul 2012 09:30:35 -0400, Michel Fortin <michel.fortin michelf.com> wrote:D/Objective-C (the compiler addition) is much more than that. It's support and cohabitation of a second object ABI, it's support for Objective-C exceptions mixed with D exceptions, support for Objective-C string and selector literals, class objects and overridable class methods, overriding, contracts added to the Objective-C object model, Objective-C protocols (through interfaces), plus a few other things which haven't been implemented at this time.Out of curiosity, do you see this becoming a possible improvement on D in the next year? I have recently been doing iOS and Mac development with objective-c, and I am quite impressed with how well it works, and how easy it is to use, especially with xcode. It would be nice to mix in a bit of D, using obj-c containers is a pain. I remember the tail-const object reference was a blocker, no? is there anything else? -Steve
Jul 12 2012
On 2012-07-12 15:48:13 +0000, "Steven Schveighoffer" <schveiguy yahoo.com> said:On Thu, 12 Jul 2012 09:30:35 -0400, Michel Fortin <michel.fortin michelf.com> wrote:Tail const is a orthogonal issue. I just don't have time to work on this right now -- I'm too busy working on other thing -- even though I'd like very much to work on that. -- Michel Fortin michel.fortin michelf.com http://michelf.com/D/Objective-C (the compiler addition) is much more than that. It's support and cohabitation of a second object ABI, it's support for Objective-C exceptions mixed with D exceptions, support for Objective-C string and selector literals, class objects and overridable class methods, overriding, contracts added to the Objective-C object model, Objective-C protocols (through interfaces), plus a few other things which haven't been implemented at this time.Out of curiosity, do you see this becoming a possible improvement on D in the next year? I have recently been doing iOS and Mac development with objective-c, and I am quite impressed with how well it works, and how easy it is to use, especially with xcode. It would be nice to mix in a bit of D, using obj-c containers is a pain. I remember the tail-const object reference was a blocker, no? is there anything else?
Jul 12 2012
On 2012-07-12 19:52, Michel Fortin wrote:I just don't have time to work on this right now -- I'm too busy working on other thing -- even though I'd like very much to work on that.It would be so, so nice to have this finished and merged upstream. -- /Jacob Carlborg
Jul 12 2012
On 2012-07-12 11:41:46 +0000, "bearophile" <bearophileHUGS lycos.com> said:Andrei Alexandrescu:I don't think templates were the culprit for the D/Objective-C bridge. Code bloat was, but that's something that was inherent to the design of the bridge. The bridge was using mixins extensively, and while I did everything I could to use regular non-mixin templates (because those can be reused when the template arguments are the same), it wasn't enough. In fact, given that all the wrapper functions written using mixins were virtual (so you could override them, which is quite a feature!) it meant they all needed to be instantiated even though they were not used anywhere. There's actually no way I could have reduced code bloat significantly even by writing all the code by hand in the most optimized way. Not unless I abandoned the capability to override functions, but that'd make the bridge almost useless. One thing that might have helped is if the linker could have striped all the classes that were not used in the final executable, something it couldn't do because all module info refers to them. But that wouldn't have helped with the compilation speed, which was becoming the second problem not far behind code bloat.The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.There is no proof that template bloat won't be a problem in D (I remember the first version of the D Objective-C bridge failing because of code bloat, the second version seems to require changes in the D language).And it seems L1 code caches of CPUs aren't growing a lot (so I suggest to not ignore having lot of code to swap in and out of those 32 kbytes). So maybe it will be useful to introduce in D some means to attack the code bloat problem from several sides at the same time. Some time ago I have suggested one of such weapons, the templated() that allows to select what parts of a struct/class are templated regarding to what template arguments (it's a refinement of an idea of Stroustrup). Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).Both desirable things, but I don't think those would have much impact on the D/Objective-C bridge. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 12 2012
On 12/07/2012 15:20, Michel Fortin wrote:On 2012-07-12 11:41:46 +0000, "bearophile" <bearophileHUGS lycos.com> said:I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.Andrei Alexandrescu:I don't think templates were the culprit for the D/Objective-C bridge. Code bloat was, but that's something that was inherent to the design of the bridge. The bridge was using mixins extensively, and while I did everything I could to use regular non-mixin templates (because those can be reused when the template arguments are the same), it wasn't enough. In fact, given that all the wrapper functions written using mixins were virtual (so you could override them, which is quite a feature!) it meant they all needed to be instantiated even though they were not used anywhere. There's actually no way I could have reduced code bloat significantly even by writing all the code by hand in the most optimized way. Not unless I abandoned the capability to override functions, but that'd make the bridge almost useless. One thing that might have helped is if the linker could have striped all the classes that were not used in the final executable, something it couldn't do because all module info refers to them. But that wouldn't have helped with the compilation speed, which was becoming the second problem not far behind code bloat.The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.There is no proof that template bloat won't be a problem in D (I remember the first version of the D Objective-C bridge failing because of code bloat, the second version seems to require changes in the D language).And it seems L1 code caches of CPUs aren't growing a lot (so I suggest to not ignore having lot of code to swap in and out of those 32 kbytes). So maybe it will be useful to introduce in D some means to attack the code bloat problem from several sides at the same time. Some time ago I have suggested one of such weapons, the templated() that allows to select what parts of a struct/class are templated regarding to what template arguments (it's a refinement of an idea of Stroustrup). Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).Both desirable things, but I don't think those would have much impact on the D/Objective-C bridge.
Jul 12 2012
On Thursday, 12 July 2012 at 14:58:29 UTC, deadalnix wrote:I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.L1 cache size is.
Jul 12 2012
On 7/12/12 11:50 AM, Roman D. Boiko wrote:On Thursday, 12 July 2012 at 14:58:29 UTC, deadalnix wrote:That must be why he mentioned that most of that code won't be executed. AndreiI think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.L1 cache size is.
Jul 12 2012
On 12/07/2012 17:51, Andrei Alexandrescu wrote:On 7/12/12 11:50 AM, Roman D. Boiko wrote:Exactly.On Thursday, 12 July 2012 at 14:58:29 UTC, deadalnix wrote:That must be why he mentioned that most of that code won't be executed. AndreiI think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.L1 cache size is.
Jul 12 2012
On Thu, 12 Jul 2012 10:58:28 -0400, deadalnix <deadalnix gmail.com> wrote:You will never ever ever convince me that 60MB for a hello world program is "the norm", and should just be accepted on any platform. -SteveBoth desirable things, but I don't think those would have much impact on the D/Objective-C bridge.I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.
Jul 12 2012
On 12/07/2012 18:09, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 10:58:28 -0400, deadalnix <deadalnix gmail.com> wrote:It depend what the function look like. if it is 60Mb + x where x is aproximatively proportional to the amount of code, it is fine.You will never ever ever convince me that 60MB for a hello world program is "the norm", and should just be accepted on any platform. -SteveBoth desirable things, but I don't think those would have much impact on the D/Objective-C bridge.I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.
Jul 12 2012
On 12-07-2012 18:33, deadalnix wrote:On 12/07/2012 18:09, Steven Schveighoffer wrote:I don't think you're going to convince your average Android/iOS user to download 60+ MB for your app. :) -- Alex Rønne Petersen alex lycus.org http://lycus.orgOn Thu, 12 Jul 2012 10:58:28 -0400, deadalnix <deadalnix gmail.com> wrote:It depend what the function look like. if it is 60Mb + x where x is aproximatively proportional to the amount of code, it is fine.You will never ever ever convince me that 60MB for a hello world program is "the norm", and should just be accepted on any platform. -SteveBoth desirable things, but I don't think those would have much impact on the D/Objective-C bridge.I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.
Jul 12 2012
On Thu, 12 Jul 2012 12:46:29 -0400, Alex R=C3=B8nne Petersen <alex lycus= .org> = wrote:On 12-07-2012 18:33, deadalnix wrote:On 12/07/2012 18:09, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 10:58:28 -0400, deadalnix <deadalnix gmail.com> wrote:Both desirable things, but I don't think those would have much impact on the D/Objective-C bridge.I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a=.big deal for any modern computer, not even for most cell phones now=You will never ever ever convince me that 60MB for a hello world =o =I don't think you're going to convince your average Android/iOS user t=program is "the norm", and should just be accepted on any platform. -SteveIt depend what the function look like. if it is 60Mb + x where x is aproximatively proportional to the amount of code, it is fine.download 60+ MB for your app. :)Right. For example, I had an app on my iPhone (that my wife downloaded)= = called "classic books", which I guess contained a few classic books. It was 500MB. I uninstalled it. No self-respecting book reading = application should be 500MB on iOS. iBooks by apple is 52.5 MB with 200= KB = in data (i.e. books) from about 19 books. That's under 60MB, and it does a hell of a lot more than print "Hello = world". Your app would get 1 star from me :) Note that I went through this exercise recently because I ran out of spa= ce = to take pictures. The size *does* make a difference on a 16GB device th= at = is used to store lots of media (pics and music). You will have less opposition on a full platform with 500GB to 1TB of di= sk = space, but notice how everyone complains that their computers run slower= = over time... My answer is usually "install less shit". -Steve
Jul 12 2012
On 2012-07-12 14:58:28 +0000, deadalnix <deadalnix gmail.com> said:I think this is not a problem as big as it is stated. Most of that code will be executed close to never, and 60Mb isn't a big deal for any modern computer, not even for most cell phones now.60Mb was only with bindings to the most fundamentals parts of Cocoa. It scales linearly with the number of classes and functions you add bindings for. It's just crazy. That's pretty much a moot point now though. The new approach, hacking the compiler, is so much better on so many levels that the old bridge looks like a joke now (even though it was impressive). I only wish I had time to dedicate to it. Perhaps next year I will. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 12 2012
On 12/07/2012 13:41, bearophile wrote:Another weapon to attack the problem is introducing in the DMD back-end an optimization (already present in LLVM, but I think not used on default), merging of functions with the same body (leaving just a jump as the body of the removed function, to keep their function pointers distinct).That is IMO the way to go instead of cluttering the language.
Jul 12 2012
deadalnix:That is IMO the way to go instead of cluttering the language.I think several solutions applied at the same time are needed if you desire to reduce bloat effectively. Bye, bearophile
Jul 12 2012
On 12/07/2012 16:55, bearophile wrote:deadalnix:The templated is redundant with that backend capability of LDC.That is IMO the way to go instead of cluttering the language.I think several solutions applied at the same time are needed if you desire to reduce bloat effectively. Bye, bearophile
Jul 12 2012
deadalnix:The templated is redundant with that backend capability of LDC.The semantics is not the same. This code doesn't compile, the compiler enforces you are not using T in code that is annotated to be a template of just V: struct Foo(T, V) { templated(V) T bar() { return T.init; } } Bye, bearophile
Jul 12 2012
On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. [...] What say you? AndreiI agree, they are not needed. seem to be so severe. Jon Skeet wrote on this long ago: http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx http://stackoverflow.com/questions/3096028/why-gethashcode-is-in-object-class
Jul 12 2012
On Thursday, 12 July 2012 at 12:06:49 UTC, Roman D. Boiko wrote:Jon Skeet wrote on this long ago:http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspxThe fact that every object has a monitor associated with it was a mistake in Java, and was unfortunately copied in .NET. This promotes the bad practice of locking on "this" and on types - both of which are typically publicly accessible references. I believe that unless a reference is exposed explicitly for the purpose of locking (like ICollection.SyncRoot) then you should avoid locking on any reference which other code knows about.This has been discussed multiple times on the D forum, I believe.
Jul 12 2012
On Thursday, 12 July 2012 at 12:36:18 UTC, RivenTheMage wrote:On Thursday, 12 July 2012 at 12:06:49 UTC, Roman D. Boiko wrote:Do you mean Monitor or all other issues from that post as well? Do you have any links? I would be interested to know conclusions.Jon Skeet wrote on this long ago:http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspxThe fact that every object has a monitor associated with it was a mistake in Java, and was unfortunately copied in .NET. This promotes the bad practice of locking on "this" and on types - both of which are typically publicly accessible references. I believe that unless a reference is exposed explicitly for the purpose of locking (like ICollection.SyncRoot) then you should avoid locking on any reference which other code knows about.This has been discussed multiple times on the D forum, I believe.
Jul 12 2012
On Thursday, 12 July 2012 at 12:43:01 UTC, Roman D. Boiko wrote:On Thursday, 12 July 2012 at 12:36:18 UTC, RivenTheMage wrote:OK, I found one myself from this post: http://michelf.com/weblog/2012/mutex-synchonization-in-d/On Thursday, 12 July 2012 at 12:06:49 UTC, Roman D. Boiko wrote:Do you mean Monitor or all other issues from that post as well? Do you have any links? I would be interested to know conclusions.Jon Skeet wrote on this long ago:http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspxThe fact that every object has a monitor associated with it was a mistake in Java, and was unfortunately copied in .NET. This promotes the bad practice of locking on "this" and on types - both of which are typically publicly accessible references. I believe that unless a reference is exposed explicitly for the purpose of locking (like ICollection.SyncRoot) then you should avoid locking on any reference which other code knows about.This has been discussed multiple times on the D forum, I believe.
Jul 12 2012
On Thursday, 12 July 2012 at 13:35:54 UTC, Roman D. Boiko wrote:OK, I found one myself from this post: http://michelf.com/weblog/2012/mutex-synchonization-in-d/Beat me :)
Jul 12 2012
On Thursday, 12 July 2012 at 12:43:01 UTC, Roman D. Boiko wrote:On Thursday, 12 July 2012 at 12:36:18 UTC, RivenTheMage wrote:Monitor issue. Here, for example: http://forum.dlang.org/thread/jq0uku$18v2$1 digitalmars.comDo you mean Monitor or all other issues from that post as well?The fact that every object has a monitor associated with it was a mistake in Java, and was unfortunately copied in .NET. This promotes the bad practice of locking on "this" and on types - both of which are typically publicly accessible references. I believe that unless a reference is exposed explicitly for the purpose of locking (like ICollection.SyncRoot) then you should avoid locking on any reference which other code knows about.This has been discussed multiple times on the D forum, I believe.
Jul 12 2012
On Thu, 12 Jul 2012 00:15:48 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community.yes, this is why we have the weird situation of object.opEquals. I'd like to get rid of that at the same time, or at least make it super-simple.2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.But C++ has no base object whatsoever! I don't think it's a fair comparison. Template bloat for small wrappers is almost non-existent (yes, the symbols are still generated) when the wrappers call virtual functions. I don't think this is an issue.3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct.Yes. Where's that new AA struct, Mr. Teoh? :)4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified.Removing those functions removes logical const as a solution, but does not invalidate the need for logical const. For example, it still would be useful to have a logical const for objects that are stored across a connection.What say you?I think this is the right approach. I always found (even since D1 days) Object.opCmp and opEquals to be very awkward, especially how you must implement the derivatives (it's much more straightforward to say specifically what objects you can compare against, vs. always having to cast from Object). Nuke 'em. -Steve
Jul 12 2012
On Thu, Jul 12, 2012 at 09:31:27AM -0400, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 00:15:48 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:[...][...] The code is still here: https://github.com/quickfur/New-AA-implementation But I got roadblocked, partially because of constness issues (ironically, the problem was that toHash, toString, etc., weren't const, and now we're talking about supporting non-const versions of them), but more because of problems with IFTI. Or at least, that's where I left it about a month ago -- then I was away on vacation and haven't had the chance to go back to the code since. :( T -- There's light at the end of the tunnel. It's the oncoming train.3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct.Yes. Where's that new AA struct, Mr. Teoh? :)
Jul 12 2012
On Thu, 12 Jul 2012 10:56:13 -0400, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:On Thu, Jul 12, 2012 at 09:31:27AM -0400, Steven Schveighoffer wrote:Hm... chicken vs. egg again... I think we need both the AA update and the removal of opX from object simultaneously. Should we start a project branch for all the components? (is that appropriate for git?) -SteveOn Thu, 12 Jul 2012 00:15:48 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:[...][...] The code is still here: https://github.com/quickfur/New-AA-implementation But I got roadblocked, partially because of constness issues (ironically, the problem was that toHash, toString, etc., weren't const, and now we're talking about supporting non-const versions of them), but more because of problems with IFTI. Or at least, that's where I left it about a month ago -- then I was away on vacation and haven't had the chance to go back to the code since. :(3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct.Yes. Where's that new AA struct, Mr. Teoh? :)
Jul 12 2012
On Thu, Jul 12, 2012 at 11:51:15AM -0400, Steven Schveighoffer wrote:On Thu, 12 Jul 2012 10:56:13 -0400, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:[...]On Thu, Jul 12, 2012 at 09:31:27AM -0400, Steven Schveighoffer wrote:[...] Having more than just me working on the AA project would be a very good thing. I don't always have the time to work on it, and it's not fair to the community that the fate of such a vital component depends on the free time schedule of one person. T -- MS Windows: 64-bit overhaul of 32-bit extensions and a graphical shell for a 16-bit patch to an 8-bit operating system originally coded for a 4-bit microprocessor, written by a 2-bit company that can't stand 1-bit of competition.Hm... chicken vs. egg again... I think we need both the AA update and the removal of opX from object simultaneously. Should we start a project branch for all the components? (is that appropriate for git?)Yes. Where's that new AA struct, Mr. Teoh? :)[...] The code is still here: https://github.com/quickfur/New-AA-implementation But I got roadblocked, partially because of constness issues (ironically, the problem was that toHash, toString, etc., weren't const, and now we're talking about supporting non-const versions of them), but more because of problems with IFTI. Or at least, that's where I left it about a month ago -- then I was away on vacation and haven't had the chance to go back to the code since. :(
Jul 12 2012
On Thursday, 12 July 2012 at 16:22:07 UTC, H. S. Teoh wrote:I don't always have the time to work on it, and it's not fair to the community that the fate of such a vital component depends on the free time schedule of one person.*cough* … DMD … *cough*.
Jul 12 2012
On 12 July 2012 18:03, David Nadlinger <see klickverbot.at> wrote:On Thursday, 12 July 2012 at 16:22:07 UTC, H. S. Teoh wrote:*cough* ... GDC ... *cough* --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0';I don't always have the time to work on it, and it's not fair to the community that the fate of such a vital component depends on the free time schedule of one person.*cough* =85 DMD =85 *cough*.
Jul 12 2012
On Thursday, 12 July 2012 at 16:22:07 UTC, H. S. Teoh wrote:I don't always have the time to work on it... but when I do... :)
Jul 12 2012
On Thursday, July 12, 2012 09:23:28 H. S. Teoh wrote:it's not fair to the community that the fate of such a vital component depends on the free time schedule of one person.True, but it does happen all too often around here (e.g. Andrei with allocators and containers). The real problem is when the person working on it disappears (e.g. someone (Tomaz?) was working on a new std.xml which was supposedy coming along fairly well, but he hasn't posted about it (or anything, I think) since some time in 2010). Still, if the work on the AA redesign could be divided up among multiple individuals and appropriately coordinated, that would help. - Jonathan M Davis
Jul 12 2012
On 12/07/2012 06:15, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? AndreiI also had a tilt on that message. This is after reflexion definitively the way to go. metaprogramming rox.
Jul 12 2012
Is this really need? The four const operators in Object should not block the user-defined mutable operators. // My purpose for 2.060 release class C { override opEquals(const Object o) const { ... } // or just alias super.opEquals opEquals; bool opEquals(Object o) { ... } // add overload for mutable object comparison } auto c1 = new C(), c2 = new C2(); c1 == c2; // the both hand side is mutable, so mutable opEquals will run In git head, it is not disallowed, but it is a *compiler bug*. To fix the problem, I have a pull request for dmd. https://github.com/D-Programming-Language/dmd/pull/1042 (The pull will kill attribute inference for const, but I think it is unnecessary for D.) ...But, I would never opposed to advancing toward the better language design. Kenji Hara 2012/7/12 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points: 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community. 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore. 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct. 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified. There are of course more angles and considerations. Walter and I discussed such for a while and concluded we should take the following route: 1. For the time being, rollback the changes. Kenji, could you please do the honors? There's no need to undo everything, only the key parts in object.d. Apologies for having to undo your work! 2. Investigate a robust migration path from the current use of opCmp, opEquals, toHash (we need to also investigate toString) to a world in which these methods don't exist in Object. In that world, associative arrays would probably be entirely generic. Ideally we should allow existing code to still work, while at the same time fostering a better style for new code. What say you? Andrei
Jul 12 2012
kenji hara:Is this really need?...But, I would never opposed to advancing toward the better language design.I am not expert on English language, but you are one of my programming heroes, so please let me try to improve a little those parts of your post :-) | Is this really necessary? | ...but, I would never be opposed to an advancement toward that better | language design. Or simply: | ...but, I am not opposed to advance to that better language design. Bye, bearophile
Jul 12 2012
On 12/07/2012 16:28, kenji hara wrote:Is this really need? The four const operators in Object should not block the user-defined mutable operators. // My purpose for 2.060 release class C { override opEquals(const Object o) const { ... } // or just alias super.opEquals opEquals; bool opEquals(Object o) { ... } // add overload for mutable object comparison } auto c1 = new C(), c2 = new C2(); c1 == c2; // the both hand side is mutable, so mutable opEquals will run In git head, it is not disallowed, but it is a *compiler bug*. To fix the problem, I have a pull request for dmd. https://github.com/D-Programming-Language/dmd/pull/1042 (The pull will kill attribute inference for const, but I think it is unnecessary for D.) ...But, I would never opposed to advancing toward the better language design.mutable and const overload of the same function is a bit weird. I'm not sure this is a bug a feature we should keep.
Jul 12 2012
On 7/12/12 10:28 AM, kenji hara wrote:Is this really need? The four const operators in Object should not block the user-defined mutable operators. // My purpose for 2.060 release class C { override opEquals(const Object o) const { ... } // or just alias super.opEquals opEquals; bool opEquals(Object o) { ... } // add overload for mutable object comparison } auto c1 = new C(), c2 = new C2(); c1 == c2; // the both hand side is mutable, so mutable opEquals will run In git head, it is not disallowed, but it is a *compiler bug*. To fix the problem, I have a pull request for dmd. https://github.com/D-Programming-Language/dmd/pull/1042 (The pull will kill attribute inference for const, but I think it is unnecessary for D.)I didn't know of that, thanks.....But, I would never opposed to advancing toward the better language design.Thanks for being so helpful and flexible! Let's discuss matters a little more in this forum before making a decision. Andrei
Jul 12 2012
On 2012-07-12 16:28, kenji hara wrote:Is this really need? The four const operators in Object should not block the user-defined mutable operators. // My purpose for 2.060 release class C { override opEquals(const Object o) const { ... } // or just alias super.opEquals opEquals; bool opEquals(Object o) { ... } // add overload for mutable object comparison } auto c1 = new C(), c2 = new C2(); c1 == c2; // the both hand side is mutable, so mutable opEquals will run In git head, it is not disallowed, but it is a *compiler bug*. To fix the problem, I have a pull request for dmd. https://github.com/D-Programming-Language/dmd/pull/1042 (The pull will kill attribute inference for const, but I think it is unnecessary for D.) ...But, I would never opposed to advancing toward the better language design. Kenji HaraI would have thought that that already worked. -- /Jacob Carlborg
Jul 12 2012
On Thursday, July 12, 2012 21:11:54 Jacob Carlborg wrote:On 2012-07-12 16:28, kenji hara wrote:The recently added attribute inferrence for overridden functions in derived types makes it impossible to have a non-const overload of a const function. - Jonathan M DavisIs this really need? The four const operators in Object should not block the user-defined mutable operators. // My purpose for 2.060 release class C { override opEquals(const Object o) const { ... } // or just alias super.opEquals opEquals; bool opEquals(Object o) { ... } // add overload for mutable object comparison> } auto c1 = new C(), c2 = new C2(); c1 == c2; // the both hand side is mutable, so mutable opEquals will run In git head, it is not disallowed, but it is a *compiler bug*. To fix the problem, I have a pull request for dmd. https://github.com/D-Programming-Language/dmd/pull/1042 (The pull will kill attribute inference for const, but I think it is unnecessary for D.) ...But, I would never opposed to advancing toward the better language design. Kenji HaraI would have thought that that already worked.
Jul 12 2012
On 2012-07-12 21:26, Jonathan M Davis wrote:The recently added attribute inferrence for overridden functions in derived types makes it impossible to have a non-const overload of a const function.I wonder if the attribute inference can be fined tuned a bit. So it's only applied to a method that is actually overridden and not overloaded. -- /Jacob Carlborg
Jul 12 2012
On Friday, July 13, 2012 08:55:58 Jacob Carlborg wrote:On 2012-07-12 21:26, Jonathan M Davis wrote:I believe that Kenji has a pull request intended to resolve the issue (probably by doing something like that, but I don't know). We'll see what Walter has to say though. - Jonathan M DavisThe recently added attribute inferrence for overridden functions in derived types makes it impossible to have a non-const overload of a const function.I wonder if the attribute inference can be fined tuned a bit. So it's only applied to a method that is actually overridden and not overloaded.
Jul 13 2012
On 2012-07-13 09:03, Jonathan M Davis wrote:I believe that Kenji has a pull request intended to resolve the issue (probably by doing something like that, but I don't know). We'll see what Walter has to say though.This one: https://github.com/D-Programming-Language/dmd/pull/1042 ? It says "We MUST kill attribute inference with const". -- /Jacob Carlborg
Jul 13 2012
On Friday, July 13, 2012 09:10:17 Jacob Carlborg wrote:On 2012-07-13 09:03, Jonathan M Davis wrote:Probably. I'd have to go dig for the associated bug report to be 100% sure, but that certainly sounds like it. - Jonathan M DavisI believe that Kenji has a pull request intended to resolve the issue (probably by doing something like that, but I don't know). We'll see what Walter has to say though.This one: https://github.com/D-Programming-Language/dmd/pull/1042 ? It says "We MUST kill attribute inference with const".
Jul 13 2012
On Thu, Jul 12, 2012 at 12:59:16AM -0700, Jonathan M Davis wrote: [...]1. Anything which wants to be able to operate on Objects generically (e.g. have a container full of Objects) is going to have problems, since comparison and hashing won't work anymore. For the standard stuff, at minimum, that will screw up being able to put Object in AAs and RedBlackTree. For 3rd party containers which decided to go the Java route of containing Objects, they risk being completely screwed.[...] What about adding this to object.di: class Hashable : Object { int opCmp(Hashable h) safe const { ... } bool opEquals(Hashable h) safe const { ... } hash_t toHash() safe const { ... } } Whatever objects need to be put in AAs can just inherit from Hashable. Or will this introduce more problems than it solves? T -- Кто везде - тот нигде.
Jul 12 2012
On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu wrote:Required reading prior to this: http://goo.gl/eXpuX You destroyed, we listened. I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points:Well, I'm not convinced it is a good idea to eliminate the stuff from Object, nor to remove const (I think RawObject as a base class of Object has merit, but to remove the Object functions for everyone? I'm very suspicious.) Some problems I would point out with the idea of "eliminate the stuff from Object and use more templates instead": 1. Most importantly, the C++ template approach is a big pain for large-scale systems, because in such systems you want to create DLLs/SOs and C++ has neither a standard ABI nor a safe way to pass around template instantiations between DLLs (in the presence of changes to internal implementation details). Similar problems exist for D, yes? It's a lot easier to define a standard ABI for classes than to solve the cross-DLL template problem. 2. Although templates are used a lot in C++, in D programs they are used even more and this proposal would increase template usage, so I'd expect the bloat problem to increase. However, merging identical functions (identical machine code) might be a sufficient solution. 3. The need for more templates slows down compilation. We know this is a huge problem in C++. 4. Template bloat is no big deal on desktops but it becomes a bigger problem as the target system gets smaller. Maybe some compromise should be made to ensure D remains powerful and capable on small targets. There were two proposals yesterday that I liked. Taken together, they address all the problems that were raised with const functions in Object: 1. Provide a 'safe workaround' for const, for caching and lazy evaluation (implement it carefully to avoid breaking the guarantees of immutable) 2. Provide a class modifier that makes immutable(_) illegal, so the class uses "logical const" instead of "physical const".
Jul 12 2012
On 7/12/12 1:40 PM, David Piepgrass wrote:1. Most importantly, the C++ template approach is a big pain for large-scale systems, because in such systems you want to create DLLs/SOs and C++ has neither a standard ABI nor a safe way to pass around template instantiations between DLLs (in the presence of changes to internal implementation details). Similar problems exist for D, yes? It's a lot easier to define a standard ABI for classes than to solve the cross-DLL template problem.The thing is, that can be done in an opt-in manner. People who want methods in the root of the hierarchy can define a root that defines them. But there's no way to opt out of inheriting Object. Basically it's nice to not force people to buy into a constrained environment without necessity.2. Although templates are used a lot in C++, in D programs they are used even more and this proposal would increase template usage, so I'd expect the bloat problem to increase. However, merging identical functions (identical machine code) might be a sufficient solution.Yah, I think we have a pretty good attack at this problem.3. The need for more templates slows down compilation. We know this is a huge problem in C++.I, too, think this is a concern.4. Template bloat is no big deal on desktops but it becomes a bigger problem as the target system gets smaller. Maybe some compromise should be made to ensure D remains powerful and capable on small targets.I think virtuals are an equally, if not worse, problem in memory-constrained systems. The simple solution people choose for such - they use them judiciously. Here actually templates may be at an advantage because of their opt-in quality.There were two proposals yesterday that I liked. Taken together, they address all the problems that were raised with const functions in Object: 1. Provide a 'safe workaround' for const, for caching and lazy evaluation (implement it carefully to avoid breaking the guarantees of immutable)We should explore this option in any case. At this point I'm starting to believe (a) we're doing the right thing by marginalizing the four methods aside from this issue, (b) caching is good for other things than this particular problem.2. Provide a class modifier that makes immutable(_) illegal, so the class uses "logical const" instead of "physical const".I think this would be considerably trickier. Andrei
Jul 12 2012
On 12/07/2012 19:51, Andrei Alexandrescu wrote:This is orthogonal to what we are dealing here.2. Provide a class modifier that makes immutable(_) illegal, so the class uses "logical const" instead of "physical const".I think this would be considerably trickier.
Jul 12 2012
On Thursday, 12 July 2012 at 17:51:32 UTC, Andrei Alexandrescu wrote:On 7/12/12 1:40 PM, David Piepgrass wrote:But is the constrained environment we're talking about really all that constrained? - 'const' is not overly harsh if the user has machanisms to make that mean 'logical const'. - regarding the 5 vtable entries (destructor, toString, toHash, opEquals, opCmp), well, that's only 20/40 bytes per process, and maybe we don't need opCmp that much. Although having these in Object seems constraining in one way, removing them is constraining in a different way: you can no longer provide collection classes for "any" object without involving templates. Wait a minute, though. Keeping in mind the problem of DLL interoperability, and the constraints on using templated + many DLLs together, what if D introduced the feature that Go and Rust have, the ability to adapt any object to a compatible interface? interface IComparable { bool opEquals(IComparable rhs); int opCmp(IComparable rhs); } class Foo { /* could contain anything */ } So let's say we remove all the methods from Object, but we still want people to be able to make a collection of "any object", such as Foo, and pass this collection between DLLs safely. Moreover we want only be a single instance of the collection class, defined in a single DLL (so this collection cannot be a template class). Since a class Foo does not declare that it implements IComparable, and it might not even contain opCmp() and opEquals(), we can't just cast to IObject. Not in the current D, anyway. But now add interface adaptation from Go/Rust. Foo might not define opEquals and opCmp itself, but any client can add those via UFCS, and the standard library would probably define opEquals via UFCS as reference equality already. Thus it is possible for any client to pretend that any class implements IComparable, by adding the missing pieces (if any) and casting to IComparable.1. Most importantly, the C++ template approach is a big pain for large-scale systems, because in such systems you want to create DLLs/SOs and C++ has neither a standard ABI nor a safe way to pass around template instantiations between DLLs (in the presence of changes to internal implementation details). Similar problems exist for D, yes? It's a lot easier to define a standard ABI for classes than to solve the cross-DLL template problem.The thing is, that can be done in an opt-in manner. People who want methods in the root of the hierarchy can define a root that defines them. But there's no way to opt out of inheriting Object. Basically it's nice to not force people to buy into a constrained environment without necessity.
Jul 12 2012
we can't just cast to IObject.Oops, I meant IComparable
Jul 12 2012
On Thursday, July 12, 2012 20:42:49 David Piepgrass wrote:- 'const' is not overly harsh if the user has machanisms to make that mean 'logical const'.That will _never_ happen. That completely destroys a number of the benefits of const, and it adds quite a bit of cognitive load in dealing with const, because all of a sudden, you have to worry about whether _this_ const means actual const or logical const. It would also complicate the compiler's handling of const by quite a bit. Not to mention, Walter hates logical const in general, so he wouldn't support it. So, no, it's not going to happen. If we get any kind of logical const, it's going to be separate from const. const always has been and always will be physical const in D. - Jonathan M Davis
Jul 12 2012
On 12/07/2012 21:27, Jonathan M Davis wrote:On Thursday, July 12, 2012 20:42:49 David Piepgrass wrote:This has been discussed and isn't as dumb as you may think. What is important for us is that const provide the guarantee to never mutate immutable data. Expressed that way, it can be loosened is some cases, in such a way that immutable data can never mutate throw const, but mutable one could. I'm not for or against that, but it is certainly something to keep in mind when facing language evolution. We have that door ready to open.- 'const' is not overly harsh if the user has machanisms to make that mean 'logical const'.That will _never_ happen. That completely destroys a number of the benefits of const, and it adds quite a bit of cognitive load in dealing with const, because all of a sudden, you have to worry about whether _this_ const means actual const or logical const. It would also complicate the compiler's handling of const by quite a bit. Not to mention, Walter hates logical const in general, so he wouldn't support it. So, no, it's not going to happen. If we get any kind of logical const, it's going to be separate from const. const always has been and always will be physical const in D. - Jonathan M Davis
Jul 12 2012
On Thu, Jul 12, 2012 at 01:51:31PM -0400, Andrei Alexandrescu wrote:On 7/12/12 1:40 PM, David Piepgrass wrote:Having a class RawObject as a superclass of Object is an equally good solution. Declare a class without a base class, and the base class defaults to Object. Explicitly write "class MyClass : RawObject" and you get a class without the stuff in Object. If you want an entire hierarchy free of the stuff in Object, just write "class MyBaseClass : RawObject" and inherit everything from it. This has the advantage of _not_ breaking any existing code, and the people who want to opt out of Object, can. [...]1. Most importantly, the C++ template approach is a big pain for large-scale systems, [...]The thing is, that can be done in an opt-in manner. People who want methods in the root of the hierarchy can define a root that defines them. But there's no way to opt out of inheriting Object. Basically it's nice to not force people to buy into a constrained environment without necessity.[...] Please also remember that caching is only _one_ of the issues. Objects that exist over the network is another use case. Objects that are partially stored in (possibly remote) database. There are many other such cases. I hope we don't neglect these other cases by focusing only on caching. T -- Why are you blatanly misspelling "blatant"? -- Branden Robinson1. Provide a 'safe workaround' for const, for caching and lazy evaluation (implement it carefully to avoid breaking the guarantees of immutable)We should explore this option in any case. At this point I'm starting to believe (a) we're doing the right thing by marginalizing the four methods aside from this issue, (b) caching is good for other things than this particular problem.
Jul 12 2012
On 7/12/12 2:50 PM, H. S. Teoh wrote:On Thu, Jul 12, 2012 at 01:51:31PM -0400, Andrei Alexandrescu wrote:As far as backward compatibility goes, I'm not sure. There's code out there that e.g. assumes Object has no supertype etc. (I wrote some.) But one thing the recent discussion brought back to attention is that opEquals and opCmp are somewhat crappy. In D, they are in fact unnecessary, so it's better to undo that entire design if we can. AndreiOn 7/12/12 1:40 PM, David Piepgrass wrote:Having a class RawObject as a superclass of Object is an equally good solution.1. Most importantly, the C++ template approach is a big pain for large-scale systems, [...]The thing is, that can be done in an opt-in manner. People who want methods in the root of the hierarchy can define a root that defines them. But there's no way to opt out of inheriting Object. Basically it's nice to not force people to buy into a constrained environment without necessity.
Jul 12 2012
On 2012-07-12 20:50, H. S. Teoh wrote:Having a class RawObject as a superclass of Object is an equally good solution. Declare a class without a base class, and the base class defaults to Object. Explicitly write "class MyClass : RawObject" and you get a class without the stuff in Object. If you want an entire hierarchy free of the stuff in Object, just write "class MyBaseClass : RawObject" and inherit everything from it. This has the advantage of _not_ breaking any existing code, and the people who want to opt out of Object, can.Exactly, this is also what Ruby 1.9 does. -- /Jacob Carlborg
Jul 12 2012
On Thursday, 12 July 2012 at 17:51:32 UTC, Andrei Alexandrescu wrote:On 7/12/12 1:40 PM, David Piepgrass wrote:+11. Most importantly, the C++ template approach is a big pain for large-scale systems, because in such systems you want to create DLLs/SOs and C++ has neither a standard ABI nor a safe way to pass around template instantiations between DLLs (in the presence of changes to internal implementation details). Similar problems exist for D, yes? It's a lot easier to define a standard ABI for classes than to solve the cross-DLL template problem.The thing is, that can be done in an opt-in manner. People who want methods in the root of the hierarchy can define a root that defines them. But there's no way to opt out of inheriting Object. Basically it's nice to not force people to buy into a constrained environment without necessity.+1. Such seams give flexibility that otherwise would be extremely hard to achieve.4. Template bloat is no big deal on desktops but it becomes a bigger problem as the target system gets smaller. Maybe some compromise should be made to ensure D remains powerful and capable on small targets.I think virtuals are an equally, if not worse, problem in memory-constrained systems. The simple solution people choose for such - they use them judiciously. Here actually templates may be at an advantage because of their opt-in quality.+2 (Especially if it would be possible to redefine 'lazy', so that it would evaluate at most once.)There were two proposals yesterday that I liked. Taken together, they address all the problems that were raised with const functions in Object: 1. Provide a 'safe workaround' for const, for caching and lazy evaluation (implement it carefully to avoid breaking the guarantees of immutable)We should explore this option in any case. At this point I'm starting to believe (a) we're doing the right thing by marginalizing the four methods aside from this issue, (b) caching is good for other things than this particular problem.
Jul 12 2012
I always wondered why toString() wasn't just to!string() in the first place, short of UFCS not being implemented for all types.
Jul 13 2012
On Friday, July 13, 2012 11:02:30 F i L wrote:I always wondered why toString() wasn't just to!string() in the first place, short of UFCS not being implemented for all types.to!string(obj) uses typeof(obj).toString for user-defined types. Even if to!string is arguably the better way to convert to a string, it still needs an implementation, and for user-defined types, that's toString. It could be argued though that we should have just used opCast(T)() if(is(T == string)) {} rather than toString. However, given the push to have a version of toString that writes to an output range or a scoped delegate rather than creating a new string, the opCast wouldn't have fit as well ultimately. - Jonathan M Davis
Jul 13 2012
On 13/07/12 11:02, F i L wrote:I always wondered why toString() wasn't just to!string() in the first place, short of UFCS not being implemented for all types.toString() comes from the days before D had templates.
Jul 13 2012
On Fri, 13 Jul 2012 05:02:30 -0400, F i L <witte2008 gmail.com> wrote:I always wondered why toString() wasn't just to!string() in the first place, short of UFCS not being implemented for all types.toString in itself is wasteful. It allocates a string that will likely be thrown away immediately. Experience has shown that unnecessary allocations == low performance, at least as far as D is concerned. Yes, to!string should work, but the method for the object should use a dchar output range as a sink, instead of converting to a string. We can build to!string on top of that. -Steve
Jul 13 2012
On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu wrote:2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.What C++ community are you in touch with? Boost?... Code bloat is still a big issue in C++, especially in embedded software for obvious reasons. It's also a big issue outside of the embedded world because more code bloat causes more I$ misses, which causes performance problems. Performance is always an issue, and considering that D's key advantage over the scripting languages is performance, this has to be a serious consideration. Additionally, more code equates with longer compile times, which again is one of D's supposed selling points. Ironically, I remember you saying a while back that compile times where a big problem at Facebook. Guess what's causing that? Perhaps not so many people complain directly about code bloat any more, but they do complain about performance, they do complain about compile times, they do complain about the size of Phobos libs, and they do complain about startup times -- these things are all attributable at least in part to code bloat. FWIW: I agree with the proposal, but let's leave the code-size-doesn't-matter attitude behind.
Jul 13 2012
On 2012-07-13 14:06, Peter Alexander wrote:Ironically, I remember you saying a while back that compile times where a big problem at Facebook. Guess what's causing that?If I recall correctly, that was due to using too many global variables and compiler that kept all the global variables in a linked list. The global variables were generate from the PHP to C++ compiler. -- /Jacob Carlborg
Jul 13 2012