July 12, 2012
On Thursday, 12 July 2012 at 13:20:47 UTC, Andrei Alexandrescu wrote:
> On 7/12/12 3:59 AM, Jonathan M Davis wrote:
>> 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

July 12, 2012
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/

July 12, 2012
On Thu, 12 Jul 2012 00:15:48 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> You destroyed, we listened.
>
> I think Christophe makes a great point. We've been all thinking inside the box but we should question the very existence of the box. Once the necessity of opCmp, opEquals, toHash, toString is being debated, we get to some interesting points:
>
> 1. Polymorphic comparisons for objects has problems even without considering interaction with qualifiers. I wrote quite a few pages about that in TDPL, which add to a lore grown within the Java community.

yes, this is why we have the weird situation of object.opEquals.  I'd like to get rid of that at the same time, or at least make it super-simple.

> 2. C++ has very, very successfully avoided the necessity of planting polymorphic comparisons in base classes by use of templates. The issue is template code bloat. My impression from being in touch with the C++ community for a long time is that virtually nobody even talks about code bloat anymore. For whatever combination of industry and market forces, it's just not an issue anymore.

But C++ has no base object whatsoever!  I don't think it's a fair comparison.

Template bloat for small wrappers is almost non-existent (yes, the symbols are still generated) when the wrappers call virtual functions.  I don't think this is an issue.

> 3. opCmp, opEquals, and toHash are all needed primarily for one thing: built-in hashes. (There's also use of them in the moribund .sort method.) The thing is, the design of built-in hashes predates the existence of templates. There are reasons to move to generic-based hashes instead of today's runtime hashes (such as the phenomenal success of templated containers in C++), so it can be argued that opCmp, opEquals, and toHash exist for reasons that are going extinct.

Yes.  Where's that new AA struct, Mr. Teoh? :)

> 4. Adding support for the likes of logical constness is possible, but gravitates between too lax and onerously complicated. Walter and I don't think the aggravation is justified.

Removing those functions removes logical const as a solution, but does not invalidate the need for logical const.  For example, it still would be useful to have a logical const for objects that are stored across a connection.

> What say you?

I think this is the right approach.  I always found (even since D1 days) Object.opCmp and opEquals to be very awkward, especially how you must implement the derivatives (it's much more straightforward to say specifically what objects you can compare against, vs. always having to cast from Object).

Nuke 'em.

-Steve
July 12, 2012
On Thursday, 12 July 2012 at 12:43:01 UTC, Roman D. Boiko wrote:
> On Thursday, 12 July 2012 at 12:36:18 UTC, RivenTheMage wrote:
>> 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/
July 12, 2012
On Thursday, 12 July 2012 at 12:43:01 UTC, Roman D. Boiko wrote:
> On Thursday, 12 July 2012 at 12:36:18 UTC, RivenTheMage wrote:
>>>
>>>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

July 12, 2012
On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 7/12/12 3:59 AM, Jonathan M Davis wrote:
>> 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
July 12, 2012
On Thursday, 12 July 2012 at 13:35:54 UTC, Roman D. Boiko wrote:

> OK, I found one myself from this post:
> http://michelf.com/weblog/2012/mutex-synchonization-in-d/

Beat me :)
July 12, 2012
On Thursday, 12 July 2012 at 13:39:54 UTC, Steven Schveighoffer wrote:
> On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> If we define alternative free generic functions in object.d for the four culprit methods (and have the compiler, druntime, and stdlib use them instead of the methods), those functions can check whether a given class object has overridden the old-style functions. In that case, that means we're dealing with legacy classes and proceed the old-style way. Otherwise, proceed the new way.
>
> Hm... I don't like this, it slows down a very basic function.
>
> I think if we want a solution that allows old code to work, why not what Timon suggested? Have a base class for Object (RawObject was suggested) that does not implement the opFunctions.  It would still break code, but would be easy to fix (just specify your class derives from Object, not RawObject).
>
> -Steve


July 12, 2012
On Thursday, 12 July 2012 at 13:41:52 UTC, Roman D. Boiko wrote:
...

ups. I meant +1.
July 12, 2012
On 7/12/12 9:39 AM, Steven Schveighoffer wrote:
> On Thu, 12 Jul 2012 09:20:47 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> 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