digitalmars.D - Logical location of template instantiations
- Lodovico Giaretta (29/29) Jun 27 2016 import std.conv, core.memory;
- Lodovico Giaretta (3/3) Jul 01 2016 Ping...
- Robert burner Schadek (3/3) Jul 01 2016 IMO, this is one of these places where theory meets practice. Do
- Lodovico Giaretta (7/10) Jul 01 2016 Yes, well, I successfully bypassed my issues with this thing, but
- Enamex (7/17) Jul 01 2016 Yeah. I don't know if it's _needed_ by enough people or by the
- Jacob Carlborg (6/9) Jul 01 2016 You're not the only one, it's been brought up before. A
- Steven Schveighoffer (4/28) Jul 01 2016 I wonder what the plans are for std.allocator on this, as I would think
- Andrei Alexandrescu (4/35) Jul 01 2016 emplace only works with accessible constructors. I understand sometimes
- Jacob Carlborg (5/7) Jul 01 2016 It's possible to bypass the protection using a pointer. An alternative
- Steven Schveighoffer (5/11) Jul 01 2016 Right, but this puts allocators at a lower footing than the GC which has...
- Basile B. (3/18) Jul 01 2016 +1
- Jacob Carlborg (4/7) Jul 01 2016 It's possible to bypass protection using pointers.
- Basile B. (8/12) Jul 01 2016 Yes it would be worth. Several ppl have already hit this wall,
- Timon Gehr (8/37) Jul 01 2016 The current module (that declares 'S') might not be the only module that...
- Steven Schveighoffer (3/10) Jul 01 2016 Emplace needs a constructor alias parameter.
- Lodovico Giaretta (3/19) Jul 01 2016 Yes, this looks like a sensible solution.
- Tofu Ninja (18/20) Jul 07 2016 That wouldn't work as emplace wouldn't be able to use the alias
- Steven Schveighoffer (14/32) Jul 07 2016 Yes, it is a problem. I still don't understand how the *calling* of a
- Tofu Ninja (6/20) Jul 07 2016 It makes sense that the aliasing a private member works, when it
- Jonathan M Davis via Digitalmars-d (29/37) Jul 07 2016 What would make sense is if the template instantiation ignored the acces...
- Timon Gehr (4/12) Jul 07 2016 No, it is way simpler than that. Just don't ever check for visibility of...
- Jonathan M Davis via Digitalmars-d (7/17) Jul 08 2016 It has to be checked at some point, otherwise using a template alias
- Timon Gehr (2/20) Jul 08 2016 (That's what I said. In any case, it is simple to implement.)
- Jonathan M Davis via Digitalmars-d (6/29) Jul 08 2016 Well, then I misunderstood what you meant. But if it's simple to impleme...
import std.conv, core.memory; struct S { int x; private this(int val) { x = val; } } void main() { auto ptr = cast(S*)GC.malloc(S.sizeof); auto s = ptr.emplace(3); } This code does not work, as the call `ptr.emplace(3)` creates a new concrete implementation of emplace with parameters `S` and `int`, which logically belongs to module std.conv, and so has no access to the private constructor. But, logically speaking, as I'm able to construct objects of S, I should also be able to emplace them (which is the same thing, logically) while inside my module. What I mean is that in this situation it would be better if the call `ptr.emplace(3)` created a new concrete implementation of emplace inside the module that called it, to have the correct access permissions. This is not the first time I run into this limitation (not only with functions, but also with structs), so I wonder: wouldn't it be worth a way to get this behaviour? Thank you for your time. Lodovico Giaretta
Jun 27 2016
Ping... Maybe I'm just saying bullshit, but... Am I really the only one who faced this need?
Jul 01 2016
IMO, this is one of these places where theory meets practice. Do what works, write a comment explaining the problem, and move on ;-)
Jul 01 2016
On Friday, 1 July 2016 at 11:45:12 UTC, Robert burner Schadek wrote:IMO, this is one of these places where theory meets practice. Do what works, write a comment explaining the problem, and move on ;-)Yes, well, I successfully bypassed my issues with this thing, but I wanted to share my thoughts about the need to express this kind of thing (i.e. to give a template instantiation the privileges of the instantiating module), and to know if someone else has some opinion on this matter.
Jul 01 2016
On Friday, 1 July 2016 at 12:08:49 UTC, Lodovico Giaretta wrote:On Friday, 1 July 2016 at 11:45:12 UTC, Robert burner Schadek wrote:Yeah. I don't know if it's _needed_ by enough people or by the language, but a way to force templates to be hijacked while being instantiated (not at point of definition but at instantiation; though I imagine this might prove troublesome for reflection and template identity, somehow) if we want to. The default hygienic behavior is great, but bypassing it when needed is not.IMO, this is one of these places where theory meets practice. Do what works, write a comment explaining the problem, and move on ;-)Yes, well, I successfully bypassed my issues with this thing, but I wanted to share my thoughts about the need to express this kind of thing (i.e. to give a template instantiation the privileges of the instantiating module), and to know if someone else has some opinion on this matter.
Jul 01 2016
On 01/07/16 11:57, Lodovico Giaretta wrote:Ping... Maybe I'm just saying bullshit, but... Am I really the only one who faced this need?You're not the only one, it's been brought up before. A solution/workaround is that "emplace" invokes the constructor using a function pointer, what will bypass the protection. -- /Jacob Carlborg
Jul 01 2016
On 6/27/16 12:25 PM, Lodovico Giaretta wrote:import std.conv, core.memory; struct S { int x; private this(int val) { x = val; } } void main() { auto ptr = cast(S*)GC.malloc(S.sizeof); auto s = ptr.emplace(3); } This code does not work, as the call `ptr.emplace(3)` creates a new concrete implementation of emplace with parameters `S` and `int`, which logically belongs to module std.conv, and so has no access to the private constructor. But, logically speaking, as I'm able to construct objects of S, I should also be able to emplace them (which is the same thing, logically) while inside my module. What I mean is that in this situation it would be better if the call `ptr.emplace(3)` created a new concrete implementation of emplace inside the module that called it, to have the correct access permissions.I wonder what the plans are for std.allocator on this, as I would think it would run into the same issues. Andrei? -Steve
Jul 01 2016
On 07/01/2016 09:08 AM, Steven Schveighoffer wrote:On 6/27/16 12:25 PM, Lodovico Giaretta wrote:emplace only works with accessible constructors. I understand sometimes it's reasonable to ask for more flexibility, but there are limitations. -- Andreiimport std.conv, core.memory; struct S { int x; private this(int val) { x = val; } } void main() { auto ptr = cast(S*)GC.malloc(S.sizeof); auto s = ptr.emplace(3); } This code does not work, as the call `ptr.emplace(3)` creates a new concrete implementation of emplace with parameters `S` and `int`, which logically belongs to module std.conv, and so has no access to the private constructor. But, logically speaking, as I'm able to construct objects of S, I should also be able to emplace them (which is the same thing, logically) while inside my module. What I mean is that in this situation it would be better if the call `ptr.emplace(3)` created a new concrete implementation of emplace inside the module that called it, to have the correct access permissions.I wonder what the plans are for std.allocator on this, as I would think it would run into the same issues. Andrei?
Jul 01 2016
On 01/07/16 15:46, Andrei Alexandrescu wrote:emplace only works with accessible constructors. I understand sometimes it's reasonable to ask for more flexibility, but there are limitations.It's possible to bypass the protection using a pointer. An alternative would be to not invoke the constructor and let the users to that themselves. -- /Jacob Carlborg
Jul 01 2016
On 7/1/16 9:46 AM, Andrei Alexandrescu wrote:On 07/01/2016 09:08 AM, Steven Schveighoffer wrote:Right, but this puts allocators at a lower footing than the GC which has no problem with private ctors. I would have expected to be able to build using allocators and private ctors. -SteveI wonder what the plans are for std.allocator on this, as I would think it would run into the same issues. Andrei?emplace only works with accessible constructors. I understand sometimes it's reasonable to ask for more flexibility, but there are limitations.
Jul 01 2016
On Friday, 1 July 2016 at 14:14:00 UTC, Steven Schveighoffer wrote:On 7/1/16 9:46 AM, Andrei Alexandrescu wrote:+1On 07/01/2016 09:08 AM, Steven Schveighoffer wrote:Right, but this puts allocators at a lower footing than the GC which has no problem with private ctors. I would have expected to be able to build using allocators and private ctors. -SteveI wonder what the plans are for std.allocator on this, as I would think it would run into the same issues. Andrei?emplace only works with accessible constructors. I understand sometimes it's reasonable to ask for more flexibility, but there are limitations.
Jul 01 2016
On 01/07/16 16:14, Steven Schveighoffer wrote:Right, but this puts allocators at a lower footing than the GC which has no problem with private ctors. I would have expected to be able to build using allocators and private ctors.It's possible to bypass protection using pointers. -- /Jacob Carlborg
Jul 01 2016
On Monday, 27 June 2016 at 16:25:27 UTC, Lodovico Giaretta wrote:[...] This is not the first time I run into this limitation (not only with functions, but also with structs), so I wonder: wouldn't it be worth a way to get this behaviour?Yes it would be worth. Several ppl have already hit this wall, including me. You can vote for this enhancement, it proposes to give a "super visual acuity" to traits such as getMember or getOverloads: https://issues.dlang.org/show_bug.cgi?id=15371 You might also look at `hasUDA` from std.traits because it used to be affected by this issue.
Jul 01 2016
On 27.06.2016 18:25, Lodovico Giaretta wrote:import std.conv, core.memory; struct S { int x; private this(int val) { x = val; } } void main() { auto ptr = cast(S*)GC.malloc(S.sizeof); auto s = ptr.emplace(3); } This code does not work, as the call `ptr.emplace(3)` creates a new concrete implementation of emplace with parameters `S` and `int`, which logically belongs to module std.conv, and so has no access to the private constructor. But, logically speaking, as I'm able to construct objects of S, I should also be able to emplace them (which is the same thing, logically) while inside my module. What I mean is that in this situation it would be better if the call `ptr.emplace(3)` created a new concrete implementation of emplace inside the module that called it, to have the correct access permissions. This is not the first time I run into this limitation (not only with functions, but also with structs), so I wonder: wouldn't it be worth a way to get this behaviour? Thank you for your time. Lodovico GiarettaThe current module (that declares 'S') might not be the only module that uses emplace to construct 'S' instances. We want to hide the constructor of 'S' from other modules, but not from the current module. But both modules get identical template instances, so either both see the private constructor (through emplace), or none does. To fix this properly, there should hence be a way for the two modules to receive distinct template instances.
Jul 01 2016
On 7/1/16 3:02 PM, Timon Gehr wrote:The current module (that declares 'S') might not be the only module that uses emplace to construct 'S' instances. We want to hide the constructor of 'S' from other modules, but not from the current module. But both modules get identical template instances, so either both see the private constructor (through emplace), or none does. To fix this properly, there should hence be a way for the two modules to receive distinct template instances.Emplace needs a constructor alias parameter. -Steve
Jul 01 2016
On Friday, 1 July 2016 at 19:13:45 UTC, Steven Schveighoffer wrote:On 7/1/16 3:02 PM, Timon Gehr wrote:Yes, this looks like a sensible solution.The current module (that declares 'S') might not be the only module that uses emplace to construct 'S' instances. We want to hide the constructor of 'S' from other modules, but not from the current module. But both modules get identical template instances, so either both see the private constructor (through emplace), or none does. To fix this properly, there should hence be a way for the two modules to receive distinct template instances.Emplace needs a constructor alias parameter. -Steve
Jul 01 2016
On Friday, 1 July 2016 at 19:13:45 UTC, Steven Schveighoffer wrote:Emplace needs a constructor alias parameter. -SteveThat wouldn't work as emplace wouldn't be able to use the alias if it was private... void main(){ import other; test!foo(); } private void foo(){} module other; void test(alias pred)(){ pred(); } other.d(5): Error: function main.foo is not accessible from module other main.d(9): Error: template instance other.test!(foo) error instantiating
Jul 07 2016
On 7/7/16 7:49 AM, Tofu Ninja wrote:On Friday, 1 July 2016 at 19:13:45 UTC, Steven Schveighoffer wrote:Yes, it is a problem. I still don't understand how the *calling* of a private function is the problem, vs. the aliasing of it. Why aren't we preventing the aliasing of the private function in the first place (if not allowed)? If you can get an alias, you should be able to call it. I understand that aliases are strange in this way. What we really need is an alias to the protection level. An explicit permission given to an external template that says "for this one instantiation, you can pretend you have access to this". A workaround, of course, is to use a delegate. I came across this when learning vibe.d, which gets around the requirement in an interesting way: https://github.com/rejectedsoftware/vibe.d/issues/1516 -SteveEmplace needs a constructor alias parameter. -SteveThat wouldn't work as emplace wouldn't be able to use the alias if it was private... void main(){ import other; test!foo(); } private void foo(){} module other; void test(alias pred)(){ pred(); } other.d(5): Error: function main.foo is not accessible from module other main.d(9): Error: template instance other.test!(foo) error instantiating
Jul 07 2016
On Thursday, 7 July 2016 at 12:39:51 UTC, Steven Schveighoffer wrote:Yes, it is a problem. I still don't understand how the *calling* of a private function is the problem, vs. the aliasing of it. Why aren't we preventing the aliasing of the private function in the first place (if not allowed)? If you can get an alias, you should be able to call it. I understand that aliases are strange in this way. What we really need is an alias to the protection level. An explicit permission given to an external template that says "for this one instantiation, you can pretend you have access to this". A workaround, of course, is to use a delegate. I came across this when learning vibe.d, which gets around the requirement in an interesting way: https://github.com/rejectedsoftware/vibe.d/issues/1516 -SteveIt makes sense that the aliasing a private member works, when it is made at the instantiation site it is perfectly visible. It only gets mucked up when the alias travels out of that context into the template where it is no longer visible.
Jul 07 2016
On Thursday, July 07, 2016 08:39:51 Steven Schveighoffer via Digitalmars-d wrote:Yes, it is a problem. I still don't understand how the *calling* of a private function is the problem, vs. the aliasing of it. Why aren't we preventing the aliasing of the private function in the first place (if not allowed)? If you can get an alias, you should be able to call it. I understand that aliases are strange in this way. What we really need is an alias to the protection level. An explicit permission given to an external template that says "for this one instantiation, you can pretend you have access to this".What would make sense is if the template instantiation ignored the access level of the aliased symbol and were the same regardless of the access level of that symbol such that the template compiled regardless, but the check for accessibility would be done at the call site. Then the template could compile with a private function just fine, but it wouldn't be callable except where the private function would be callable. I suppose that that could get a bit hairy though when you consider multiple levels, since if you had something like void foo(alias pred, Arg)(Arg arg) { bar(pred)(arg); } void bar(alias pred, Arg)(Arg arg) { pred(arg); } to work even with foo and bar in different modules so long as foo were called in a place where the function being passed to it were callable. So, the buck would have to be passed at every point that the symbol were passed as an alias argument such that the check for accessibility was only done when the symbol first became an alias. Regardless, while that idea makes theoretical sense, I'm not sure that it makes sense from the standpoint of how alias parameters are currently implemented. I'm inclined to think though that something along those lines would be the best solution (at least from a usability perspective, not necessarily from the compiler's perspective). - Jonathan M Davis
Jul 07 2016
On 07.07.2016 17:11, Jonathan M Davis via Digitalmars-d wrote:So, the buck would have to be passed at every point that the symbol were passed as an alias argument such that the check for accessibility was only done when the symbol first became an alias. ...No, it is way simpler than that. Just don't ever check for visibility of the symbol accessed through an alias.Regardless, while that idea makes theoretical sense, I'm not sure that it makes sense from the standpoint of how alias parameters are currently implemented.That ought to be completely irrelevant.
Jul 07 2016
On Thursday, July 07, 2016 23:20:28 Timon Gehr via Digitalmars-d wrote:On 07.07.2016 17:11, Jonathan M Davis via Digitalmars-d wrote:It has to be checked at some point, otherwise using a template alias parameter would allow you to completely bypass the accessibility modifiers. It's just that it seems like it should be checked at the point where the symbol is passed to the template and not within the template itself, whereas right now, it's checked within the template. - Jonathan M DavisSo, the buck would have to be passed at every point that the symbol were passed as an alias argument such that the check for accessibility was only done when the symbol first became an alias. ...No, it is way simpler than that. Just don't ever check for visibility of the symbol accessed through an alias.
Jul 08 2016
On 08.07.2016 09:45, Jonathan M Davis via Digitalmars-d wrote:On Thursday, July 07, 2016 23:20:28 Timon Gehr via Digitalmars-d wrote:(That's what I said. In any case, it is simple to implement.)On 07.07.2016 17:11, Jonathan M Davis via Digitalmars-d wrote:It has to be checked at some point, otherwise using a template alias parameter would allow you to completely bypass the accessibility modifiers. It's just that it seems like it should be checked at the point where the symbol is passed to the template and not within the template itself, whereas right now, it's checked within the template. - Jonathan M DavisSo, the buck would have to be passed at every point that the symbol were passed as an alias argument such that the check for accessibility was only done when the symbol first became an alias. ...No, it is way simpler than that. Just don't ever check for visibility of the symbol accessed through an alias.
Jul 08 2016
On Friday, July 08, 2016 15:08:35 Timon Gehr via Digitalmars-d wrote:On 08.07.2016 09:45, Jonathan M Davis via Digitalmars-d wrote:Well, then I misunderstood what you meant. But if it's simple to implement, then it seems to me that it's almost certainly the way we should go. It would solve the accessibility problem in a clean way without having to instantiate the template extra times. - Jonathan M DavisOn Thursday, July 07, 2016 23:20:28 Timon Gehr via Digitalmars-d wrote:(That's what I said. In any case, it is simple to implement.)On 07.07.2016 17:11, Jonathan M Davis via Digitalmars-d wrote:It has to be checked at some point, otherwise using a template alias parameter would allow you to completely bypass the accessibility modifiers. It's just that it seems like it should be checked at the point where the symbol is passed to the template and not within the template itself, whereas right now, it's checked within the template. - Jonathan M DavisSo, the buck would have to be passed at every point that the symbol were passed as an alias argument such that the check for accessibility was only done when the symbol first became an alias. ...No, it is way simpler than that. Just don't ever check for visibility of the symbol accessed through an alias.
Jul 08 2016