digitalmars.D.learn - Is it possible to "overload" based on visibility?
- 60rntogo (51/51) Sep 23 2020 There are really two questions here, one that I intended to ask
- Steven Schveighoffer (7/15) Sep 23 2020 This is a bug in the language. Either varying ONLY by visibility of an
- aliak (3/4) Sep 23 2020 🤯😆
- 60rntogo (20/21) Sep 25 2020 Is this a known bug? If not, it should be reported.
- Steven Schveighoffer (11/37) Sep 25 2020 I don't know, you can search for and report it here:
- 60rntogo (10/15) Sep 25 2020 I find it quite hard to search for anything here, but I couldn't
- Steven Schveighoffer (8/19) Sep 25 2020 in does not mean "take by reference", it means "scope const"
- 60rntogo (9/14) Sep 25 2020 I'm not sure that I really understand scope, but I read
- Steven Schveighoffer (10/19) Sep 25 2020 That's new, unreleased (available in 2.094.0), and requires the
- Steven Schveighoffer (3/4) Sep 25 2020 *yet*.
- 60rntogo (9/12) Sep 25 2020 Yes, I understand that. What I'm really after at this point is
- H. S. Teoh (19/30) Sep 25 2020 You probably need to use the long-form of templates, with separate
- 60rntogo (4/7) Sep 26 2020 Alright, but your example still contains shouldReturnByRef which
- aliak (11/19) Sep 23 2020 Yeah, you can make a property setter:
- 60rntogo (5/7) Sep 23 2020 I'm aware of this, but it does not achieve what I asked for. It
There are really two questions here, one that I intended to ask and one that came out while I was trying to figure out the answer. Consider this simple code: --- module foo; struct Foo { private int _x; int x() const { return _x; } } --- If I have an instance of Foo outside of the module I can read the value of _x using the property method x, but I can only modify it from inside the module using the name _x. This is exactly the kind of encapsulation that I often want, but I'm wondering if this could be improved a little. It would be nice if I didn't have to remember if I need to use _x or x depending on the context. Instead I would like to use only one name, say x, from both inside and outside of the module and have compiler complain if I'm trying to modify it from the outside. My naive attempt was this: --- import std : writeln; private int _x; private ref int x() return { writeln("ref int"); return _x; } int x() const { writeln("int"); return _x; } --- At first I didn't even expect this to compile, but it does and I can call these methods. I believe an overload is chosen based on the type qualifier of a Foo instance. What is truly unexpected is that if I call x on a mutable object even outside of the module, then the first overload is called! So my questions are: 1. Can I achieve my original goal of being able to refer to _x by one name, so that I have read only access from outside the module and read/write access from inside? 2. Is the behavior that allows me to call the private method intended? This is such a blatant violation of encapsulation that it feels like a bug either in the language or the implementation.
Sep 23 2020
On 9/23/20 2:38 PM, 60rntogo wrote:So my questions are: 1. Can I achieve my original goal of being able to refer to _x by one name, so that I have read only access from outside the module and read/write access from inside?I would guess no. You have to use different names.2. Is the behavior that allows me to call the private method intended? This is such a blatant violation of encapsulation that it feels like a bug either in the language or the implementation.This is a bug in the language. Either varying ONLY by visibility of an overload should be disallowed, or you shouldn't have access to the private x. I don't know which one the answer is, but certainly the current behavior is erroneous. -Steve
Sep 23 2020
On Wednesday, 23 September 2020 at 19:27:13 UTC, Steven Schveighoffer wrote:This is a bug in the language.🤯😆
Sep 23 2020
On Wednesday, 23 September 2020 at 19:27:13 UTC, Steven Schveighoffer wrote:This is a bug in the language.Is this a known bug? If not, it should be reported. I came up with an answer to my original question that sort of works: --- module foo; struct Foo { private int x; } int x(Foo f) { return f.x; } --- The downside is that if I don't want to import all of foo at once, then I have to import both Foo and x, but then I can read x from outside the module and modify it form inside as I wanted. Are there any drawbacks of this approach that I'm not seeing?
Sep 25 2020
On 9/25/20 3:43 AM, 60rntogo wrote:On Wednesday, 23 September 2020 at 19:27:13 UTC, Steven Schveighoffer wrote:I don't know, you can search for and report it here: https://issues.dlang.orgThis is a bug in the language.Is this a known bug? If not, it should be reported.I came up with an answer to my original question that sort of works: --- module foo; struct Foo { Â private int x; } int x(Foo f) { Â return f.x; } --- The downside is that if I don't want to import all of foo at once, then I have to import both Foo and x, but then I can read x from outside the module and modify it form inside as I wanted. Are there any drawbacks of this approach that I'm not seeing?Wow, this is actually quite clever! I think it's a very valid solution. The only thing I would caution is that it takes Foo by value, which means it's going to make a copy of everything. Your toy example, that's OK, but if Foo is complex or has a significant copy constructor, it might be slow. You can use auto ref to alleviate that: int x()(auto ref Foo f) // needs to be a template for auto ref to work -Steve
Sep 25 2020
On Friday, 25 September 2020 at 13:15:27 UTC, Steven Schveighoffer wrote:I don't know, you can search for and report it here: https://issues.dlang.orgI find it quite hard to search for anything here, but I couldn't find anything similar so I submitted a bug report.You can use auto ref to alleviate that: int x()(auto ref Foo f) // needs to be a template for auto ref to workThat's a good point, thanks. Since we are on that topic, how would that differ from the following? int x(in Foo f) And going further, if instead of int I wanted to return something that might also be expensive to copy, what would be the best way to declare the function?
Sep 25 2020
On 9/25/20 10:12 AM, 60rntogo wrote:On Friday, 25 September 2020 at 13:15:27 UTC, Steven Schveighoffer wrote:ou can use auto ref to alleviate that:in does not mean "take by reference", it means "scope const"int x()(auto ref Foo f) // needs to be a template for auto ref to workThat's a good point, thanks. Since we are on that topic, how would that differ from the following? int x(in Foo f)And going further, if instead of int I wanted to return something that might also be expensive to copy, what would be the best way to declare the function?It depends on if you want to return a copy. If you want to return a reference if the source is a reference, use auto ref on the return as well. But if you still want to protect the internal data, it would have to be const. -Steve
Sep 25 2020
On Friday, 25 September 2020 at 14:21:59 UTC, Steven Schveighoffer wrote:in does not mean "take by reference", it means "scope const"I'm not sure that I really understand scope, but I read https://dlang.org/spec/function.html#param-storage as saying "in means take by value or reference depending on what is better optimized". Is that not what we want here?It depends on if you want to return a copy. If you want to return a reference if the source is a reference, use auto ref on the return as well. But if you still want to protect the internal data, it would have to be const.Right, again I'm wondering if there is a way of saying "just figure out if it's more optimal to return by value or const reference".
Sep 25 2020
On 9/25/20 11:13 AM, 60rntogo wrote:On Friday, 25 September 2020 at 14:21:59 UTC, Steven Schveighoffer wrote:That's new, unreleased (available in 2.094.0), and requires the -preview=in switch. I wouldn't depend on that mechanism yes.in does not mean "take by reference", it means "scope const"I'm not sure that I really understand scope, but I read https://dlang.org/spec/function.html#param-storage as saying "in means take by value or reference depending on what is better optimized". Is that not what we want here?Right, again I'm wondering if there is a way of saying "just figure out if it's more optimal to return by value or const reference".If the input is not ref, you should not return by ref, because then you would be returning a reference to local stack data that is about to be destroyed. The only way to say "make this const ONLY if it's ref" is to overload the function with the proper attributes for the proper situations. Otherwise, you can just return const auto ref. -Steve
Sep 25 2020
On 9/25/20 11:21 AM, Steven Schveighoffer wrote:I wouldn't depend on that mechanism yes.*yet*. -Steve
Sep 25 2020
On Friday, 25 September 2020 at 15:21:22 UTC, Steven Schveighoffer wrote:If the input is not ref, you should not return by ref, because then you would be returning a reference to local stack data that is about to be destroyed.Yes, I understand that. What I'm really after at this point is that I would like to write a clever mixin that would handle all of these decisions for me. It should generate a function that takes arguments and returns the result by value or const reference depending on what is more appropriate for the given types. I was under the impression that this could be accomplished using in or some other qualifiers.
Sep 25 2020
On Fri, Sep 25, 2020 at 05:58:08PM +0000, 60rntogo via Digitalmars-d-learn wrote:On Friday, 25 September 2020 at 15:21:22 UTC, Steven Schveighoffer wrote:You probably need to use the long-form of templates, with separate function declarations, to accomplish this. E.g.: template myFunc(Args...) { static if (shouldReturnByRef!Args) ref ReturnType myFunc(Args args) { ... // implementation here } else // non-ref return ReturnType myFunc(Args args) { ... // implementation here } } The reason is that `ref` return is an attribute of the *function*, not the return type, so you can't just use an `auto` return type and have the compiler infer it. T -- What doesn't kill me makes me stranger.If the input is not ref, you should not return by ref, because then you would be returning a reference to local stack data that is about to be destroyed.Yes, I understand that. What I'm really after at this point is that I would like to write a clever mixin that would handle all of these decisions for me. It should generate a function that takes arguments and returns the result by value or const reference depending on what is more appropriate for the given types. I was under the impression that this could be accomplished using in or some other qualifiers.
Sep 25 2020
On Friday, 25 September 2020 at 18:58:54 UTC, H. S. Teoh wrote:You probably need to use the long-form of templates, with separate function declarations, to accomplish this. E.g.: ...Alright, but your example still contains shouldReturnByRef which presumably I need to implement myself. But that's an optimization detail that I'd rather leave up to the compiler, is that possible?
Sep 26 2020
On Wednesday, 23 September 2020 at 18:38:53 UTC, 60rntogo wrote:There are really two questions here, one that I intended to ask and one that came out while I was trying to figure out the answer. Consider this simple code: [...]Yeah, you can make a property setter: private void x(int newValue) { _x = newValue }2. Is the behavior that allows me to call the private method intended? This is such a blatant violation of encapsulation that it feels like a bug either in the language or the implementation.Definitely sounds like a bug! Feels like this has got to be a regression because I just tried this: struct Foo { private void f() {} void f(int i) {} } And Foo.f() is callable from outside the module: https://run.dlang.io/is/FVyw7u
Sep 23 2020
On Wednesday, 23 September 2020 at 19:26:43 UTC, aliak wrote:Yeah, you can make a property setter: private void x(int newValue) { _x = newValue }I'm aware of this, but it does not achieve what I asked for. It only allows me to assign to _x, it doesn't give me a reference to x, so I cannot use it with say += or any other function that takes int by mutable reference.
Sep 23 2020