www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - All right, all right! Interim decision regarding qualified Object

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu 
wrote:
 Required reading prior to this: http://goo.gl/eXpuX
Referenced post (for context):
 The problem is not only in the constness of the argument, but 
 also in
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.
Jul 11 2012
parent travert phare.normalesup.org (Christophe Travert) writes:
"Mehrdad" , dans le message (digitalmars.D:172012), a écrit :
 On Thursday, 12 July 2012 at 04:15:48 UTC, Andrei Alexandrescu 
 wrote:
 Required reading prior to this: http://goo.gl/eXpuX
Referenced post (for context):
 The problem is not only in the constness of the argument, but 
 also in
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.
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.
Jul 12 2012
prev sibling next sibling parent "Chris NS" <ibisbasenji gmail.com> writes:
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
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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?

 Andrei
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. 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
parent travert phare.normalesup.org (Christophe Travert) writes:
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
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
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 nicely
How 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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, July 12, 2012 11:07:42 Mehrdad wrote:
 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 nicely
How would we expect people to deal with these const issues when the issues come up in their own libraries? Or do we not care?
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 Davis
Jul 12 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
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
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
parent reply "Mehrdad" <wfunction hotmail.com> writes:
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 
 not
Say 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
parent reply Mike Parker <aldacron gmail.com> writes:
On 07/13/2012 10:04 AM, Mehrdad wrote:
 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 not
Say 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()?
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?
Jul 12 2012
next sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
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
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, July 13, 2012 03:15:41 Mehrdad wrote:
 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()?"?
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 Davis
Jul 12 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
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
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, July 13, 2012 10:10:14 Mike Parker wrote:
 On 07/13/2012 10:04 AM, Mehrdad wrote:
 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 not
Say 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()?
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?
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 Davis
Jul 12 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
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
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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?
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.
 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=1824
 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. -Steve
Jul 12 2012
parent "Mehrdad" <wfunction hotmail.com> writes:
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=1824
Thanks 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.
 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.
Well I'm not understanding the point of this post then... though thanks for letting me know I guess.
Jul 12 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, July 13, 2012 03:30:36 Mehrdad wrote:
 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?
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.
 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
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:
 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.
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 Davis
Jul 12 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 11:51, Jonathan M Davis wrote:
 On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:
 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.
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 Davis
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.
Jul 12 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/12/2012 2:51 AM, Jonathan M Davis wrote:
 On Thursday, July 12, 2012 02:43:09 Walter Bright wrote:
 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.
Which is why we'll be leaving those members in Object for the foreseeable future.
Jul 12 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 12 July 2012 at 13:20:47 UTC, Andrei Alexandrescu 
wrote:
 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
+1
Jul 12 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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.
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
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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
parent "Roman D. Boiko" <rb d-coding.com> writes:
On Thursday, 12 July 2012 at 13:41:52 UTC, Roman D. Boiko wrote:
...

ups. I meant +1.
Jul 12 2012
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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:

 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.
Hm... I don't like this, it slows down a very basic function.
It's one comparison.
 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
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Too complicated. I think we can afford one comparison.
An annotation for old style classes? Bye, bearophile
Jul 12 2012
prev sibling next sibling parent "Roman D. Boiko" <rb d-coding.com> writes:
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
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 15:49, Andrei Alexandrescu wrote:
 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:

 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.
Hm... I don't like this, it slows down a very basic function.
It's one comparison.
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.
Jul 12 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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:
 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.
Hm... I don't like this, it slows down a very basic function.
It's one comparison.
 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.
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. -Steve
Jul 12 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 12 Jul 2012 14:43:57 -0400, Jacob Carlborg <doob me.com> wrote:

 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.
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. -Steve
Jul 12 2012
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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!
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. -Steve
Jul 12 2012
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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:

 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!
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 == obj2 instead of obj1.opEquals(obj2), but I assume quite a few override opEquals and rely on it being called. Andrei
Jul 12 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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.
(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. -Steve
Jul 12 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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:
 On 7/12/12 4:50 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 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.
(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)
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 Davis
Jul 12 2012
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling parent reply "Mehrdad" <wfunction hotmail.com> writes:
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
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 That raises an interesting point. With these changes, what should  
 opEquals' signature be for classes?
How about inout?
No. opEquals returns bool. -Steve
Jul 12 2012
parent reply "Mehrdad" <wfunction hotmail.com> writes:
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:

 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?
No. opEquals returns bool. -Steve
I meant more like bool opEquals(inout Object other) inout;
Jul 12 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 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:
 That raises an interesting point. With these changes, what should  
 opEquals' signature be for classes?
How about inout?
No. opEquals returns bool. -Steve
I meant more like bool opEquals(inout Object other) inout;
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; -Steve
Jul 13 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 13 Jul 2012 02:49:01 -0400, Jacob Carlborg <doob me.com> wrote:

 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.
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. -Steve
Jul 13 2012
prev sibling next sibling parent reply Don Clugston <dac nospam.com> writes:
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?

 Andrei
Well: * 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
parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:
 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?

 Andrei
Well: * 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.
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. -- Paulo
Jul 12 2012
parent reply Don Clugston <dac nospam.com> writes:
On 12/07/12 12:00, Paulo Pinto wrote:
 On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:
 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?

 Andrei
Well: * 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.
I don't find them that weird, because many OO languages do have them.
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???
Jul 12 2012
parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Thursday, 12 July 2012 at 11:03:37 UTC, Don Clugston wrote:
 On 12/07/12 12:00, Paulo Pinto wrote:
 On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:
 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?

 Andrei
Well: * 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.
I don't find them that weird, because many OO languages do have them.
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???
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. -- Paulo
Jul 12 2012
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
 "bearophile"  wrote in message 
 news:xrbtkoercscroxgtodcu forum.dlang.org...
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
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. -- Paulo
Jul 12 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 13:21, bearophile wrote:
 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
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.
Jul 12 2012
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
next sibling parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
 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
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 13:50, Tobias Pankrath 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).
Why not drop that requirement? What is the use case of different function pointers for different but equivalent functions? Does anyone depend on this?
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.
Jul 12 2012
prev sibling next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"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
parent "bearophile" <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2012-07-12 13:01:42 +0000, "bearophile" <bearophileHUGS lycos.com> said:

 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... :-)
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.
 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.
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/
Jul 12 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
parent reply Michel Fortin <michel.fortin michelf.com> writes:
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:
 
 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?
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/
Jul 12 2012
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2012-07-12 11:41:46 +0000, "bearophile" <bearophileHUGS lycos.com> said:

 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).
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.
  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
parent reply deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 15:20, Michel Fortin wrote:
 On 2012-07-12 11:41:46 +0000, "bearophile" <bearophileHUGS lycos.com> said:

 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).
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.
 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.
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
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/12/12 11:50 AM, Roman D. Boiko wrote:
 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.
That must be why he mentioned that most of that code won't be executed. Andrei
Jul 12 2012
parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 17:51, Andrei Alexandrescu wrote:
 On 7/12/12 11:50 AM, Roman D. Boiko wrote:
 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.
That must be why he mentioned that most of that code won't be executed. Andrei
Exactly.
Jul 12 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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 program is "the norm", and should just be accepted on any platform. -Steve
Jul 12 2012
parent reply deadalnix <deadalnix gmail.com> writes:
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 program is "the norm", and should just be accepted on any platform. -Steve
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.
Jul 12 2012
parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
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 program is "the norm", and should just be accepted on any platform. -Steve
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.
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.org
Jul 12 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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  =
 program
 is "the norm", and should just be accepted on any platform.

 -Steve
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.
I don't think you're going to convince your average Android/iOS user t=
o =
 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
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 16:55, bearophile wrote:
 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
The templated is redundant with that backend capability of LDC.
Jul 12 2012
parent "bearophile" <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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?

 Andrei
I 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
parent reply "RivenTheMage" <riven-mage id.ru> writes:
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.aspx
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
parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
 Jon Skeet wrote on this long ago:
http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx
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.
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.
Jul 12 2012
next sibling parent reply "Roman D. Boiko" <rb d-coding.com> writes:
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:
 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.aspx
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.
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.
OK, I found one myself from this post: http://michelf.com/weblog/2012/mutex-synchonization-in-d/
Jul 12 2012
parent "RivenTheMage" <riven-mage id.ru> writes:
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
prev sibling parent "RivenTheMage" <riven-mage id.ru> writes:
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:
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.
Do you mean Monitor or all other issues from that post as well?
Monitor issue. Here, for example: http://forum.dlang.org/thread/jq0uku$18v2$1 digitalmars.com
Jul 12 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
[...]
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? :)
[...] 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.
Jul 12 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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:
 On Thu, 12 Jul 2012 00:15:48 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
[...]
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? :)
[...] 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. :(
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?) -Steve
Jul 12 2012
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
[...]
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. :(
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?)
[...] 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.
Jul 12 2012
next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
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
parent Iain Buclaw <ibuclaw ubuntu.com> writes:
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:
 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*.
*cough* ... GDC ... *cough* --=20 Iain Buclaw *(p < e ? p++ : p) =3D (c & 0x0f) + '0';
Jul 12 2012
prev sibling parent "Mehrdad" <wfunction hotmail.com> writes:
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
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
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?

 Andrei
I also had a tilt on that message. This is after reflexion definitively the way to go. metaprogramming rox.
Jul 12 2012
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
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
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
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
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
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 Hara
I would have thought that that already worked. -- /Jacob Carlborg
Jul 12 2012
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, July 12, 2012 21:11:54 Jacob Carlborg wrote:
 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 Hara
I would have thought that that already worked.
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 Davis
Jul 12 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, July 13, 2012 08:55:58 Jacob Carlborg wrote:
 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.
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 Davis
Jul 13 2012
parent reply Jacob Carlborg <doob me.com> writes:
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
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, July 13, 2012 09:10:17 Jacob Carlborg wrote:
 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".
Probably. I'd have to go dig for the associated bug report to be 100% sure, but that certainly sounds like it. - Jonathan M Davis
Jul 13 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
prev sibling next sibling parent reply "David Piepgrass" <qwertie256 gmail.com> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 19:51, Andrei Alexandrescu wrote:
 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.
This is orthogonal to what we are dealing here.
Jul 12 2012
prev sibling next sibling parent reply "David Piepgrass" <qwertie256 gmail.com> writes:
On Thursday, 12 July 2012 at 17:51:32 UTC, Andrei Alexandrescu 
wrote:
 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.
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.
Jul 12 2012
next sibling parent "David Piepgrass" <qwertie256 gmail.com> writes:
 we can't just cast to IObject.
Oops, I meant IComparable
Jul 12 2012
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
parent deadalnix <deadalnix gmail.com> writes:
On 12/07/2012 21:27, Jonathan M Davis wrote:
 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
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.
Jul 12 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jul 12, 2012 at 01:51:31PM -0400, Andrei Alexandrescu wrote:
 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, [...]
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.
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. 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.
[...] 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 Robinson
Jul 12 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/12/12 2:50 PM, H. S. Teoh wrote:
 On Thu, Jul 12, 2012 at 01:51:31PM -0400, Andrei Alexandrescu wrote:
 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, [...]
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.
Having a class RawObject as a superclass of Object is an equally good solution.
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. Andrei
Jul 12 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
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
prev sibling parent "Roman D. Boiko" <rb d-coding.com> writes:
On Thursday, 12 July 2012 at 17:51:32 UTC, Andrei Alexandrescu 
wrote:
 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.
+1
 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.
+1. Such seams give flexibility that otherwise would be extremely hard to achieve.
 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 (Especially if it would be possible to redefine 'lazy', so that it would evaluate at most once.)
Jul 12 2012
prev sibling next sibling parent reply "F i L" <witte2008 gmail.com> writes:
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
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
prev sibling next sibling parent Don Clugston <dac nospam.com> writes:
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
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
prev sibling parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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