December 27, 2011
On 12/26/11 7:25 PM, Peter Alexander wrote:
> Following up to this, how do I access non-function members of the held
> object? e.g.
>
> struct Foo
> {
> int x = 1;
> }
>
> void main()
> {
> RefCounted!Foo f;
> writeln(f.x); // Doesn't work
> }

We can easily have opDispatch look at field names. But I think it's poor design to expose bald data anyway.

> Also, what about template member functions of the held object?
>
> struct Foo
> {
> int get(int X)() { return X; }
> }
>
> void main()
> {
> RefCounted!Foo f;
> writeln(f.get!123()); // Doesn't work either
> }

This is a problem.


Andrei
December 27, 2011
On 12/27/11, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> We can easily have opDispatch look at field names. But I think it's poor design to expose bald data anyway.

opDispatch doesn't work with property functions, or opBinary, or opOpAssign. And what about the ctor? I can't call the ctor with your RefCounted.
December 27, 2011
On 27/12/11 1:29 AM, Andrei Alexandrescu wrote:
> We can easily have opDispatch look at field names. But I think it's poor
> design to expose bald data anyway.

I disagree, especially with immutable structs. There's no point wrapping immutable data in functions or properties.


>> Also, what about template member functions of the held object?
>>
>> struct Foo
>> {
>> int get(int X)() { return X; }
>> }
>>
>> void main()
>> {
>> RefCounted!Foo f;
>> writeln(f.get!123()); // Doesn't work either
>> }
>
> This is a problem.

I would recommend postponing any major additions to Phobos that use opDispatch to forward calls until it has been investigated in full. I am not convinced that it can be used seamlessly without some relatively large changes to the language.

Another potential problem of the top of my head: what about operator overloads on the held object? Just forward from opUnary/opBinary etc.?

What about held objects that overload opAssign?

What if the held object is itself a RefCounted?

December 27, 2011
On 12/26/11 11:25 AM, Andrei Alexandrescu wrote:
[snip]
> Destroy.

Walter indeed just destroyed me over the phone: I conflated reference counting with copy-on-write. Essentially instead of defining a reference type that's garbage-collected, I defined a value type that has cow.

Which is not bad! Check out the quick fix at http://pastebin.com/HHw06qrc.

With that, cow is a sheer policy. With the magic of opDispatch it looks like we can define reference counted containers _and_ value containers - all in very little code.

The perspectives here are extremely exciting. The question remains how to best package this awesome array of options to maximize coherence. So we have:

1. "Basic" containers - reference semantics, using classic garbage collection

2. Reference counted containers - still reference semantics, using reference counting

3. COW containers - value semantics, using reference counting to make copying O(1).

How to we provide an Apple-style nice wrapping to all of the above?


Andrei


December 27, 2011
On 12/26/11 7:49 PM, Andrej Mitrovic wrote:
> On 12/27/11, Andrei Alexandrescu<SeeWebsiteForEmail@erdani.org>  wrote:
>> We can easily have opDispatch look at field names. But I think it's poor
>> design to expose bald data anyway.
>
> opDispatch doesn't work with property functions,

It actually does, as per the unittests. Even if it currently does by @property being too lax, it should continue to work.

> or opBinary,

Should work, as operators are just translated to regular methods.

> or
> opOpAssign.

Should work.

> And what about the ctor? I can't call the ctor with your
> RefCounted.

Well, construction is a delicate topic. Currently RefCounted handles all construction internally, e.g. it doesn't take over a pointer to an existing instance (as C++'s shared_ptr does). So construction of objects needs to be handled by RefCounted itself - e.g. by forwarding constructor parameters.


Andrei
December 27, 2011
On 12/26/11 8:23 PM, Peter Alexander wrote:
> On 27/12/11 1:29 AM, Andrei Alexandrescu wrote:
>> We can easily have opDispatch look at field names. But I think it's poor
>> design to expose bald data anyway.
>
> I disagree, especially with immutable structs. There's no point wrapping
> immutable data in functions or properties.

Good point. It can be done.

Embedded type aliases are more of a problem, but still doable. For example say DListImpl defines a type DListImpl!(T).Range inside - that should be accessible also as DList!(T).Range.

>>> Also, what about template member functions of the held object?
>>>
>>> struct Foo
>>> {
>>> int get(int X)() { return X; }
>>> }
>>>
>>> void main()
>>> {
>>> RefCounted!Foo f;
>>> writeln(f.get!123()); // Doesn't work either
>>> }
>>
>> This is a problem.
>
> I would recommend postponing any major additions to Phobos that use
> opDispatch to forward calls until it has been investigated in full.

We're a long way from adding to Phobos, so no need to worry.

> I am
> not convinced that it can be used seamlessly without some relatively
> large changes to the language.

I repeat that opDispatch and auto ref were invented for this, so anything that doesn't work now is a bug. There are no changes needed to the language, only fix the bugs :o).

> Another potential problem of the top of my head: what about operator
> overloads on the held object? Just forward from opUnary/opBinary etc.?

Will work.

> What about held objects that overload opAssign?

Already works.

> What if the held object is itself a RefCounted?

Well I'd say it should all work as expected!


Andrei
December 27, 2011
On 2011-12-27 02:47:50 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> On 12/26/11 11:25 AM, Andrei Alexandrescu wrote:
> [snip]
>> Destroy.
> 
> Walter indeed just destroyed me over the phone: I conflated reference counting with copy-on-write. Essentially instead of defining a reference type that's garbage-collected, I defined a value type that has cow.
> 
> Which is not bad! Check out the quick fix at http://pastebin.com/HHw06qrc.
> 
> With that, cow is a sheer policy. With the magic of opDispatch it looks like we can define reference counted containers _and_ value containers - all in very little code.
> 
> The perspectives here are extremely exciting. The question remains how to best package this awesome array of options to maximize coherence. So we have:
> 
> 1. "Basic" containers - reference semantics, using classic garbage collection
> 
> 2. Reference counted containers - still reference semantics, using reference counting
> 
> 3. COW containers - value semantics, using reference counting to make copying O(1).
> 
> How to we provide an Apple-style nice wrapping to all of the above?

Apple just doesn't give you this kind of options. It picks one for you, documents the semantics and keep the implementation opaque. Containers in Objective-C are regular objects, so they follow object semantics (not that I like it though).

Ideally for D we'd follow the natural language semantics, where the first would be a DList*, the second is a RefCounted!DList, and the last is a RefCopy!DList. The only "problem" is that the default 'DList' is a value-type and it seems you don't want that to be the default. Unfortunately, I don't think there is a clean way to solve this: there are just too many options, some who must be implemented by library types and another by a language type. Reminds me of Rebindable…

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

December 27, 2011
On 12/27/11, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> It actually does, as per the unittests. Even if it currently does by @property being too lax, it should continue to work.

It actually doesn't:

struct FooImpl
{
    int _x;
    @property int x() { return _x; }
    @property void x(int val) { _x = val; }

    auto dup() { return FooImpl(); }
    auto dispose() { }
}

void main()
{
    RefCounted!FooImpl foo;
    foo.x = 1;  // NG
}

Sure you could make a property return ref, but that's circumventing the setter and allowing direct access to the field from client-code. I've ran into this issue before when playing with opDispatch but I couldn't figure out a workaround.

>
>> or opBinary,
>
> Should work, as operators are just translated to regular methods.
>
>> or
>> opOpAssign.
>
> Should work.
>

Doesn't seem to work:

struct FooImpl
{
    auto opBinary(string op)(int val) { return this; }
    void opOpAssign(string op)(int val) { }
    auto dup() { return FooImpl(); }
    auto dispose() { }
}

void main()
{
    RefCounted!FooImpl foo;
    auto f = foo + 1;  // ng
    foo += 1;  // ng
}

> So construction of objects
> needs to be handled by RefCounted itself - e.g. by forwarding
> constructor parameters.

But it doesn't do that currently?
December 27, 2011
On Mon, 26 Dec 2011 17:30:54 -0800, Peter Alexander <peter.alexander.au@gmail.com> wrote:

> On 27/12/11 1:14 AM, Robert Jacques wrote:
>> On Mon, 26 Dec 2011 17:09:02 -0800, Peter Alexander
>>> If the held object has a method with the same name as RefCounted (e.g.
>>> asConst) then how do you call the held object's method instead of
>>> RefCounted's method?
>>
>> You, can't. Looking at the source code asConst is a private member
>> function and therefore, given we are using opDispatch for forwarding,
>> these methods should have _ or __ prepended onto them.
>
> Identifiers starting with __ are reserved, which leaves you with _,
> which could be used by the held object also.

Yes, in theory, but no in practice. It's perfectly possible to use __name or __name__ in user code, just highly not recommended. And while I'd never do that in my user code, I think the runtime and the standard library should be able to use __ (or maybe ___) when needed.
December 27, 2011
On Mon, 26 Dec 2011 19:00:57 -0800, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 12/26/11 7:49 PM, Andrej Mitrovic wrote:
>> On 12/27/11, Andrei Alexandrescu<SeeWebsiteForEmail@erdani.org>  wrote:
>>> We can easily have opDispatch look at field names. But I think it's poor
>>> design to expose bald data anyway.
>>
>> opDispatch doesn't work with property functions,
>
> It actually does, as per the unittests. Even if it currently does by
> @property being too lax, it should continue to work.

Currently, if opDispatch is only templated on a string, property assignment (i.e. foo.x = 1) syntax works. If opDispatch is templated on more than the method name, DMD 2.057 ICEes.

>> or opBinary,
>
> Should work, as operators are just translated to regular methods.
>
>> or
>> opOpAssign.
>
> Should work.

But not in practice yet; DMD still treats opBinary, opAssign, etc as being special and doesn't forward them to opDispatch. However, it's straightforward to manually define them yourself.