Thread overview | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 30, 2010 discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Hello, When 2 constructors (*) accept the same number of parameters, the only remaining discrimination is type. Right? But some language types (or machine types) can have very diverse _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different: this (int[] data, string filename) {...} this (int[] data, string message) {...} Aliasing like in alias string Name; does not help since for D Name is still string. I know about typedef, but it is not even mentionned in TDPL, so I guess it is on the deprecation path. (Am I right?) So, what is the solution for this? (I added a 3rd fake bool parameter in one case) Things get more complicated with unsigned integers: they can be used as ordinals (index, which one), as cardinals (count, how many), as any of the char types. These are completely different semantics for the "modeller" (the programmer), but for the language (thus for the machine) they are the same semantics. Things get worse with template parameterisation, a case I lately met: Struct S (Element) { this (int[] data, string message) {...} this (int[] data, Element element) {...} What happens when Element is string? Below an example: struct S(Typ) { this(int) {writeln("int");} this(Typ) {writeln("Typ");} } unittest { auto s1 = S!string(1); auto s1 = S!int(1); } ==> rdmd -w -debug -unittest -L--export-dynamic --build-only -of"__trials__" "__trials__.d" __trials__.d(42): Error: constructor __trials__.S!(int).S.this called with argument types: ((int)) matches both: __trials__.S!(int).S.this(int _param_0) and: __trials__.S!(int).S.this(int _param_0) Compilation failed. How do you cope with such cases? Denis (*) or any other func, in fact, but the issue shows up more frequently on constructors, because they have good reasons to accept various parameter sets. -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com |
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to spir | Why not have something like this: this (int[] data, string text, bool isMessage = false) {...} Then, if you just pass in two parameters you treat it as a filename and if you pass in a "true" for the third parameter, it's a message. It's not quite what you're looking for, but it's simple and pretty clean. Casey |
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to spir | spir:
> But some language types (or machine types) can have very diverse _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different:
You may wrap your data in a struct.
Bye,
bearophile
|
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to sybrandy | sybrandy wrote:
> Why not have something like this:
>
> this (int[] data, string text, bool isMessage = false) {...}
>
> Then, if you just pass in two parameters you treat it as a filename and if you pass in a "true" for the third parameter, it's a message. It's not quite what you're looking for, but it's simple and pretty clean.
>
> Casey
If you opt for this solution, an enum is slightly more verbose but much clearer:
enum IsMessage
{
Yes,
No
}
this (int[] data, string text, IsMessage isMessage = IsMessage.No) {...}
auto s = new S(data, text, IsMessage.Yes);
vs
auto s = new S(data, text, true);
I would still prefer a factory method or a struct wrapper though.
|
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to sybrandy | On Thu, 30 Dec 2010 08:04:29 -0500
sybrandy <sybrandy@gmail.com> wrote:
> Why not have something like this:
>
> this (int[] data, string text, bool isMessage = false) {...}
>
> Then, if you just pass in two parameters you treat it as a filename and if you pass in a "true" for the third parameter, it's a message. It's not quite what you're looking for, but it's simple and pretty clean.
>
> Casey
That's what I did, precisely, and yes the fake param is bool. (thought I had mentioned this in the OP, maybe forgot, sorry).
Denis
-- -- -- -- -- -- --
vit esse estrany ☣
spir.wikidot.com
|
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Thu, 30 Dec 2010 08:15:51 -0500
bearophile <bearophileHUGS@lycos.com> wrote:
> > But some language types (or machine types) can have very diverse _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different:
>
> You may wrap your data in a struct.
Yes, thank you for this hint. A kind of proxy struct? It can indeed be used everywhere performance is not critical. But a side issue is that it requires the 'alias this' hack, I guess, or forwarding every operation to the actual, but wrapped, element. What do you think
Denis
-- -- -- -- -- -- --
vit esse estrany ☣
spir.wikidot.com
|
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Attachments:
| On Thu, Dec 30, 2010 at 12:18 PM, spir <denis.spir@gmail.com> wrote: > On Thu, 30 Dec 2010 08:15:51 -0500 > bearophile <bearophileHUGS@lycos.com> wrote: > > > > But some language types (or machine types) can have very diverse > _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different: > > > > You may wrap your data in a struct. > > Yes, thank you for this hint. A kind of proxy struct? It can indeed be used everywhere performance is not critical. But a side issue is that it requires the 'alias this' hack, I guess, or forwarding every operation to the actual, but wrapped, element. What do you think > > Denis > -- -- -- -- -- -- -- > vit esse estrany ☣ > > spir.wikidot.com > > Why is performance harmed by the use of a struct? Wouldn't it be zero-overhead like C++'s std::auto_ptr? Also, the alias this and the forward might be a real good solution. And a mixin like Luger's might be jackpot, really. I just dislike the use in: func2(Position(1)); // implicit conversion to int with alias this I guess that can be actually a bug, not a feature :) Maybe one day the function signature changes slightly and the problem is further disguised because "you're obviously passing the right Position here"... when it's actually an "int count" thing. The "alias this" thing is a good shorthand when assigning, though: int a = pos; // implicit conversion from Position to int instead of int b = pos.base; -- Atenciosamente / Sincerely, Guilherme ("n2liquid") Vieira |
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger Blijdestijn | On 12/30/2010 08:46 AM, Lutger Blijdestijn wrote: > sybrandy wrote: > >> Why not have something like this: >> >> this (int[] data, string text, bool isMessage = false) {...} >> >> Then, if you just pass in two parameters you treat it as a filename and >> if you pass in a "true" for the third parameter, it's a message. It's >> not quite what you're looking for, but it's simple and pretty clean. >> >> Casey > > If you opt for this solution, an enum is slightly more verbose but much > clearer: > > enum IsMessage > { > Yes, > No > } > > this (int[] data, string text, IsMessage isMessage = IsMessage.No) {...} > > > auto s = new S(data, text, IsMessage.Yes); > > vs > > auto s = new S(data, text, true); I will agree that is clearer. I just had to do stuff like this for different reasons and it worked very nicely. > > > I would still prefer a factory method or a struct wrapper though. True, I just don't know how without it being complex. I think this may be the case where improvements to the type system would be useful. For me, this situation doesn't come up very often, so I'm not all that concerned, but I do see where this can be useful. I'm just not a fan of having to write a lot of code to do something that the language can turn into something simple. However, another possible solution that just occurred to me is something like this (please forgive any typos, I haven't done inheritance in D yet): enum TextType { Filename, Message } class Text { string text; TextType type; bool isMessage() { return TextType.Message == this.type; } } class Filename : Text { this(int[] data, string txt) { this.type = TextType.Filename; this.text = txt; // Do something with data... } } class Message : Text { this(int[] data, string txt) { this.type = TextType.Message; this.text = txt; // Do something with data... } } Then, you can do something like this: Text foo = new Filename(data, filename); Text bar = new Message(data, message); Not sure if it's any better than using an enum, but it still has the clarity that you're looking for. Casey |
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to Guilherme Vieira | Guilherme Vieira wrote: > On Thu, Dec 30, 2010 at 12:18 PM, spir <denis.spir@gmail.com> wrote: > >> On Thu, 30 Dec 2010 08:15:51 -0500 >> bearophile <bearophileHUGS@lycos.com> wrote: >> >> > > But some language types (or machine types) can have very diverse >> _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different: >> > >> > You may wrap your data in a struct. >> >> Yes, thank you for this hint. A kind of proxy struct? It can indeed be used everywhere performance is not critical. But a side issue is that it requires the 'alias this' hack, I guess, or forwarding every operation to the actual, but wrapped, element. What do you think >> >> Denis >> -- -- -- -- -- -- -- >> vit esse estrany ☣ >> >> spir.wikidot.com >> >> > Why is performance harmed by the use of a struct? Wouldn't it be zero-overhead like C++'s std::auto_ptr? > > Also, the alias this and the forward might be a real good solution. And a mixin like Luger's might be jackpot, really. I just dislike the use in: > > func2(Position(1)); // implicit conversion to int with alias this This is deliberate, in this case I think of Position as a subtype of int so it is entirely reasonable to implicitly convert it. With opDispatch and operator overloading you could achieve the semantics you are after though. > I guess that can be actually a bug, not a feature :) Maybe one day the function signature changes slightly and the problem is further disguised because "you're obviously passing the right Position here"... when it's actually an "int count" thing. The "alias this" thing is a good shorthand when assigning, though: > > int a = pos; // implicit conversion from Position to int instead of int b = pos.base; > |
December 30, 2010 Re: discrimination of constructors with same number of parameters | ||||
---|---|---|---|---|
| ||||
Posted in reply to spir | On Thu, 30 Dec 2010 05:50:55 -0500, spir <denis.spir@gmail.com> wrote: > Hello, > > > When 2 constructors (*) accept the same number of parameters, the only remaining discrimination is type. Right? But some language types (or machine types) can have very diverse _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different: > this (int[] data, string filename) {...} > this (int[] data, string message) {...} > Aliasing like in > alias string Name; > does not help since for D Name is still string. > > I know about typedef, but it is not even mentionned in TDPL, so I guess it is on the deprecation path. (Am I right?) So, what is the solution for this? (I added a 3rd fake bool parameter in one case) What I would suggest is static factory methods. The issue with any kind of typedef (be it with the soon-to-be-deprecated typedef keyword or with a proxy struct), is that what does this mean? auto obj = new Foo([1, 2, 3], "blah"); Is "blah" a filename or a message? Whereas, if you use factory methods: auto obj = Foo.createWithFilename([1,2,3], "blah"); // "blah" is a filename auto obj = Foo.createWithMessage([1,2,3], "blah"); // "blah" is a message The code becomes crystal clear. Reduce verbosity as you see fit ;) I've used this kind of method with creating exceptions in C#, where I want to generate a message based on the data instead of having to redundantly specify both the message and the data. -Steve |
Copyright © 1999-2021 by the D Language Foundation