Jump to page: 1 2
Thread overview
Coming back, Unique, opDot and whatever else
Jan 17, 2014
Stanislav Blinov
Jan 17, 2014
Stanislav Blinov
Jan 17, 2014
qznc
Jan 17, 2014
Stanislav Blinov
Jan 17, 2014
Jacob Carlborg
Jan 17, 2014
Stanislav Blinov
Jan 17, 2014
Jacob Carlborg
Jan 17, 2014
Stanislav Blinov
Jan 18, 2014
Stanislav Blinov
Jan 18, 2014
Jacob Carlborg
Jan 18, 2014
Stanislav Blinov
Jan 18, 2014
Jacob Carlborg
Jan 19, 2014
Rory McGuire
Jan 19, 2014
Stanislav Blinov
January 17, 2014
Hello everyone! It's been a long time since I last posted here, I've been away from all things D, only being able to take an occasional peek from time to time. It's so good to be back. I'm now finding a bit of time to commit to learn D, more relearn as it would seem.

I've started my rediscoveries with exploring of concurrency, parallelism, threading in D, and after some time I found myself thinking "I need a unique encapsulator". Don't ask why, I may not even be able to answer it in a month. But that helped me solve some problems before in C++, so I thought why not try it here? In a couple of page views I came upon std.typecons and its Unique type. And I thought "why that is exactly what I want!". And it was, too. But after taking a closer look at its general implementation I just couldn't help myself but think "well, it seems it was done in a hurry, never finished, left as it was because this of that and whatnot". I mean, those sparse comments, things like "doesn't work yet", etc... I thought well, since I'm learning the language again, why not make it an exercise and fill those blanks? It'd certainly help me, because it would improve the abstraction I'm using, and because it's a learning experience.

So, here's what I came up with for now:

http://codepad.org/S4TfIdxc

Granted, not a complete implementation, keeping not very far from the original. But right now I think it's a good time to ask you guys what do you think? Where have I went wrong, what did I do incorrectly, what potential issues can you spot in this? I mean, I'm not asking about using opDot(), which, as I understand it, could be going away anytime now. At least I think I managed to fill in most of the "blanks" of the current implementation while keeping (almost?) to the same interface. In short, please destroy this with Big Fat Phazerz so I could take the remaining ashes and contemplate on the next iteration :)
January 17, 2014
Oh woops, it seems I misclicked the links and ended up posing in .announce instead of .learn. Sorry about that! If this is in any way movable, I'd be obliged. Thanks!
January 17, 2014
On Friday, 17 January 2014 at 01:12:04 UTC, Stanislav Blinov wrote:
> Hello everyone! It's been a long time since I last posted here, I've been away from all things D, only being able to take an occasional peek from time to time. It's so good to be back. I'm now finding a bit of time to commit to learn D, more relearn as it would seem.
>
> I've started my rediscoveries with exploring of concurrency, parallelism, threading in D, and after some time I found myself thinking "I need a unique encapsulator". Don't ask why, I may not even be able to answer it in a month. But that helped me solve some problems before in C++, so I thought why not try it here? In a couple of page views I came upon std.typecons and its Unique type. And I thought "why that is exactly what I want!". And it was, too. But after taking a closer look at its general implementation I just couldn't help myself but think "well, it seems it was done in a hurry, never finished, left as it was because this of that and whatnot". I mean, those sparse comments, things like "doesn't work yet", etc... I thought well, since I'm learning the language again, why not make it an exercise and fill those blanks? It'd certainly help me, because it would improve the abstraction I'm using, and because it's a learning experience.
>
> So, here's what I came up with for now:
>
> http://codepad.org/S4TfIdxc
>
> Granted, not a complete implementation, keeping not very far from the original. But right now I think it's a good time to ask you guys what do you think? Where have I went wrong, what did I do incorrectly, what potential issues can you spot in this? I mean, I'm not asking about using opDot(), which, as I understand it, could be going away anytime now. At least I think I managed to fill in most of the "blanks" of the current implementation while keeping (almost?) to the same interface.

Improving Phobos code by filling in the blanks is usually a good idea and a good learning experience as well.

Changing an interface in Phobos is a big deal and should be thoroughly justified. Does it break backwards compatibility? Why is it necessary?

(btw moving to .learn is not possible, unfortunately)
January 17, 2014
On 2014-01-17 02:12, Stanislav Blinov wrote:
> Hello everyone! It's been a long time since I last posted here, I've
> been away from all things D, only being able to take an occasional peek
> from time to time. It's so good to be back. I'm now finding a bit of
> time to commit to learn D, more relearn as it would seem.
>
> I've started my rediscoveries with exploring of concurrency,
> parallelism, threading in D, and after some time I found myself thinking
> "I need a unique encapsulator". Don't ask why, I may not even be able to
> answer it in a month. But that helped me solve some problems before in
> C++, so I thought why not try it here? In a couple of page views I came
> upon std.typecons and its Unique type. And I thought "why that is
> exactly what I want!". And it was, too. But after taking a closer look
> at its general implementation I just couldn't help myself but think
> "well, it seems it was done in a hurry, never finished, left as it was
> because this of that and whatnot". I mean, those sparse comments, things
> like "doesn't work yet", etc... I thought well, since I'm learning the
> language again, why not make it an exercise and fill those blanks? It'd
> certainly help me, because it would improve the abstraction I'm using,
> and because it's a learning experience.
>
> So, here's what I came up with for now:
>
> http://codepad.org/S4TfIdxc
>
> Granted, not a complete implementation, keeping not very far from the
> original. But right now I think it's a good time to ask you guys what do
> you think? Where have I went wrong, what did I do incorrectly, what
> potential issues can you spot in this? I mean, I'm not asking about
> using opDot(), which, as I understand it, could be going away anytime
> now. At least I think I managed to fill in most of the "blanks" of the
> current implementation while keeping (almost?) to the same interface. In
> short, please destroy this with Big Fat Phazerz so I could take the
> remaining ashes and contemplate on the next iteration :)

opDot has been replaced with opDispatch [1] and "alias this" [2]. Why can't @safe be used, can you use @trusted instead? You should probably use template constraints for "createUnique" as well. As for coding style, especially if you're aiming for including in Phobos:

* Function names never start with underscore and always starts with a lowercase letter

* I would prefer the same for instance variables as well, but I know there are several cases in Phobos where instance variables starts with an underscore

[1] http://dlang.org/operatoroverloading.html#Dispatch
[2] http://dlang.org/class.html#AliasThis

-- 
/Jacob Carlborg
January 17, 2014
On Friday, 17 January 2014 at 06:25:53 UTC, qznc wrote:

> Improving Phobos code by filling in the blanks is usually a good idea and a good learning experience as well.

Oh, I wasn't proposing to stick that into Phobos, not in its current state. I'm not that arrogant :) Even given that I resolve all the TODOs that are currently there, it'd need a lot of discussion beforehand to even be proposed.

> Changing an interface in Phobos is a big deal and should be thoroughly justified. Does it break backwards compatibility? Why is it necessary?

Yes, it does. It disallows things like Unique!Car shiny = new Lamborghini(), which are possible in std Unique and are analagous to Unique!Car dubious = createCarAndSneakilySaveLotsOfReferencesToIt().
Initialization is completely taken over by createUnique(), which is basically a non-member implementation of this(Args...)(Args args) (commented out in typecons).

Of course, Unique can not prevent the type itself to advertise aliases all over the application, but that's something that can't be enforced anyway.

Also, its type support is currently very limited (std Unique can have just about anything that can be new'ed), but that's temporary, I'll be extending that.

Other than these, I can't think of any other friction with current implementation. Though I'd have to write tests to be sure.

> (btw moving to .learn is not possible, unfortunately)

:(
January 17, 2014
On Friday, 17 January 2014 at 07:34:58 UTC, Jacob Carlborg wrote:

> opDot has been replaced with opDispatch [1] and "alias this" [2].

I know, it was just a shortcut "for now". Although alias this is of little help in case of Unique, at least without additional "middle man". After all, the whole purpose of Unique is to swallow the reference and never let anyone outside the family lay hands on it :)

Surely, opDot() is not a panacea either, you can always steal a reference by doing auto x = u.opDot().

I was thinking about brewing up a middle man using reflection. A hypothetical PublicInterface(T) mixin which could dispatch function calls with opDispatch and public data access with its own properties. But that's limiting. I haven't completely thought it over yet, and am open for suggestions :)

> Why can't @safe be used, can you use @trusted instead?

As far as I understand it, it can. I mean, I don't see where I would violate any of the rules attached to @safe. The only danger zone is dereference, and that's protected by throwing. But I commented it out because I started having doubts: in my unittests (they're in separate module so they have the same access as the user code would) I have three simple classes that don't have any @safe attributes on their functions. Unique would fail to compile with those ("failed semantic analysis"). So it would seem it's rather restrictive. I don't mind imposing correctness, but how far should it go?

> You should probably use template constraints for "createUnique" as well.

In my opinion, static assert allows for nicer error messages.

> As for coding style, especially if you're aiming for including in Phobos:

If only in some distant future :)

> * Function names never start with underscore and always starts with a lowercase letter

Oh, yeah, those. Those would go away outside, as private members of a module :)

But that brings another point. No matter how opDot() could be replaced (be it alias this or that potential mixin I mentioned), Unique does have a public method of its own (release()). How would one resolve collisions in this case? I mean, if a wrapped object has its own release() method? In the opDot() case, one can write x.opDot().release(). Could similar be done with alias this?

> * I would prefer the same for instance variables as well, but I know there are several cases in Phobos where instance variables starts with an underscore

Got it, thanks!
January 17, 2014
On 2014-01-17 16:18, Stanislav Blinov wrote:

> As far as I understand it, it can. I mean, I don't see where I would
> violate any of the rules attached to @safe. The only danger zone is
> dereference, and that's protected by throwing. But I commented it out
> because I started having doubts: in my unittests (they're in separate
> module so they have the same access as the user code would) I have three
> simple classes that don't have any @safe attributes on their functions.
> Unique would fail to compile with those ("failed semantic analysis"). So
> it would seem it's rather restrictive. I don't mind imposing
> correctness, but how far should it go?

Just try and @safe and see what happens. These really are the cases where you can rely on the compiler telling you when you're do something wrong.

> In my opinion, static assert allows for nicer error messages.

Yes, I agree. We had a discussion about this recently. I don't recall now, but there are some other advantages of using template constrains. Like it's working properly with __traits(compile).

> Oh, yeah, those. Those would go away outside, as private members of a
> module :)

Doesn't matter, private could should look just as good as public ;)

> But that brings another point. No matter how opDot() could be replaced
> (be it alias this or that potential mixin I mentioned), Unique does have
> a public method of its own (release()). How would one resolve collisions
> in this case? I mean, if a wrapped object has its own release() method?
> In the opDot() case, one can write x.opDot().release(). Could similar be
> done with alias this?

I don't think so, but via opDispatch you can do:

x.opDispatch!("release")();

-- 
/Jacob Carlborg
January 17, 2014
On Friday, 17 January 2014 at 20:06:08 UTC, Jacob Carlborg wrote:

>> Unique would fail to compile with those ("failed semantic analysis"). So
>> it would seem it's rather restrictive. I don't mind imposing
>> correctness, but how far should it go?
>
> Just try and @safe and see what happens. These really are the cases where you can rely on the compiler telling you when you're do something wrong.

Ahem. Wasn't it what I said? :) Of course I did try. My concern is that it would stop accepting arbitrary user types. Most times this would be a good thing. But not always. Hence I'm hesitating :)

>> In my opinion, static assert allows for nicer error messages.
>
> Yes, I agree. We had a discussion about this recently. I don't recall now, but there are some other advantages of using template constrains. Like it's working properly with __traits(compile).

Hmm... That's an interesting notice, I'd need to investigate. Thank you.

>> Oh, yeah, those. Those would go away outside, as private members of a
>> module :)
>
> Doesn't matter, private could should look just as good as public ;)

Oh, I didn't say so, but of course once they're out of class, they're bound to have proper names. I don't know if you've caught that comment in the code, but I basically intentionally named them ugly to minimize collisions.

>> In the opDot() case, one can write x.opDot().release(). Could similar be
>> done with alias this?
>
> I don't think so, but via opDispatch you can do:
>
> x.opDispatch!("release")();

Heh, now I'm even more leaning towards a proxy. Because honestly, x.opDispatch!("release")() is even uglier than x.opDot().release() :D By proxy I mean replacing opDot() with a mixin that would directly inject a Unique with an interface of a wrapped object. That has some problems (like how to forward calls to template functions), but hey, I'm experimenting here!

It also occured to me that with alias this you could do something like (cast(X)x).release()... which may or may not do what one expects, and that (in case of both opDot() and alias this) would depend on what exactly do those return (a copy, a reference, etc.).
January 18, 2014
On Friday, 17 January 2014 at 20:25:37 UTC, Stanislav Blinov wrote:

> Heh, now I'm even more leaning towards a proxy. Because honestly, x.opDispatch!("release")() is even uglier than x.opDot().release() :D...

Well, what can I say? I didn't need to go very far. Because Phobos has such proxy. Which is called std.typecons.Proxy :) I skimmed over it in the docs several times, probably because the docs just say "Make proxy for a." without going into much detail. But the last time I spotted it, associative memory kicked in, I guess, and I stayed a bit longer to actually look at the example.

There is, however, at least one issue with it: template arguments are not forwarded properly:

---
class Widget {
  auto inconsistent(T...)(T args) if (T.length) { return args[0]; }
}

auto widget = new Widget;
widget.inconsistent("hello", 10, 20); // works

auto uwidget = createUnique!Widget();
uwidget.inconsistent("hello", 10, 20); // Error: template instance inconsistent!() does not match template declaration inconsistent(T...)(T args) if (T.length)
uwidget.inconsistent!(string,int,int)("hello", 10, 20); //works
---

I hadn't had a chance for a closer inspection yet as to why though. In any case, that Proxy is a nice thing to have in the library!
January 18, 2014
On 2014-01-17 21:25, Stanislav Blinov wrote:

> Ahem. Wasn't it what I said? :)

I don't know, perhaps I missed that :)

> Of course I did try. My concern is that
> it would stop accepting arbitrary user types. Most times this would be a
> good thing. But not always. Hence I'm hesitating :)

Right, but the opposite could be said as well. If it's not marked with @safe no other functions marked with @safe can call the function. But any non-safe function can call @safe functions.

> Oh, I didn't say so, but of course once they're out of class, they're
> bound to have proper names. I don't know if you've caught that comment
> in the code, but I basically intentionally named them ugly to minimize
> collisions.

I didn't think of that. Perhaps using two underscores instead then, since the compiler is has reserved those names no one else should use them. I think this is an edge case where this could be allowed.

Alternatively, as you wrote in a comment, use free functions. Since they would be declared in the same module they would have access to the private data. Hmm, but the compiler prefers opDispatch before UFCS.

> Heh, now I'm even more leaning towards a proxy. Because honestly,
> x.opDispatch!("release")() is even uglier than x.opDot().release() :D By
> proxy I mean replacing opDot() with a mixin that would directly inject a
> Unique with an interface of a wrapped object. That has some problems
> (like how to forward calls to template functions), but hey, I'm
> experimenting here!

Does opDot even work?

-- 
/Jacob Carlborg
« First   ‹ Prev
1 2