www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - public aliases to private/package symbols

reply "Martin Nowak" <dawg dawgfoto.de> writes:
Should aliases be allowed to raise the accessibility of a symbol?

http://d.puremagic.com/issues/show_bug.cgi?id=4533
http://d.puremagic.com/issues/show_bug.cgi?id=6013
Jan 24 2012
next sibling parent Trass3r <un known.com> writes:
 Should aliases be allowed to raise the accessibility of a symbol?
Yeah I do use that by having a private template function and public aliases to certain instances.
Jan 24 2012
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Martin Nowak" <dawg dawgfoto.de> wrote in message 
news:mailman.782.1327427928.16222.digitalmars-d puremagic.com...
 Should aliases be allowed to raise the accessibility of a symbol?

 http://d.puremagic.com/issues/show_bug.cgi?id=4533
 http://d.puremagic.com/issues/show_bug.cgi?id=6013
Yes.
Jan 24 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:jfnag6$317n$1 digitalmars.com...
 "Martin Nowak" <dawg dawgfoto.de> wrote in message 
 news:mailman.782.1327427928.16222.digitalmars-d puremagic.com...
 Should aliases be allowed to raise the accessibility of a symbol?

 http://d.puremagic.com/issues/show_bug.cgi?id=4533
 http://d.puremagic.com/issues/show_bug.cgi?id=6013
Yes.
How else are you going to separate the interface for the internal implementation of a template from its for-public-consumption interface? This whole issue is literally *NO* different from "Should a public pointer/reference be allowed to point to private data?" or "Should a public function be allowed to expose a private one?" The answer is: "Obviously yes". I don't understand why anyone thinks this is any different just because they're aliases instead of pointers/references/functions/etc. All the arguments against public alias to private symbols apply equally to these questions too, and in those cases nobody would even question it. What is it about aliases that suddenly trips people up and makes them think the whole concept of accessibility should be flipped around on its head?
Jan 24 2012
parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Tuesday, 24 January 2012 at 22:26:37 UTC, Nick Sabalausky 
wrote:
 This whole issue is literally *NO* different from "Should a 
 public pointer/reference be allowed to point to private data?" 
 or "Should a public function be allowed to expose a private 
 one?" The answer is: "Obviously yes".
Things can be obvious in different ways. For example, one could argue that it's also obvious that an alias should behave exactly the same as the thing it aliases. Allowing aliases to change protection would break that. For the record, I agree that the answer should be "yes", but it's not a decision that should be made rashly. If we aren't careful, we could introduce a hole in the protection system in a non-obvious way. C++'s protection system has a non-obvious hole: http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html Again, I agree, but what's obvious isn't always true, so it needs to be considered in depth.
Jan 24 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/25/2012 12:09 AM, Peter Alexander wrote:
 On Tuesday, 24 January 2012 at 22:26:37 UTC, Nick Sabalausky wrote:
 This whole issue is literally *NO* different from "Should a public
 pointer/reference be allowed to point to private data?" or "Should a
 public function be allowed to expose a private one?" The answer is:
 "Obviously yes".
Things can be obvious in different ways. For example, one could argue that it's also obvious that an alias should behave exactly the same as the thing it aliases. Allowing aliases to change protection would break that.
The accessibility of something is not part of its behavior.
 For the record, I agree that the answer should be "yes", but it's not a
 decision that should be made rashly. If we aren't careful, we could
 introduce a hole in the protection system in a non-obvious way. C++'s
 protection system has a non-obvious hole:
 http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html
Non-obvious? Perfectly obvious: Access checking rules do not apply to names in explicit template instantiations. It is an explicit rule that states access checking is subverted.
 Again, I agree, but what's obvious isn't always true, so it needs to be
 considered in depth.
Accessibility-raising aliases are trivially safe, because the alias declaration must have access to the aliased symbol.
Jan 24 2012
parent reply "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Wednesday, 25 January 2012 at 00:08:25 UTC, Timon Gehr wrote:
 Accessibility-raising aliases are trivially safe, because the 
 alias declaration must have access to the aliased symbol.
You are probably right about not introducing holes, but I can imagine this getting tricky, and perhaps confusing in some cases. Here are some off the top of my head. module A; private class Foo {} public alias Foo Bar; In other modules that import A: Bar b = new typeof(b)(); // typeof(b) is Foo. Is this allowed? T foo(T)(T x) { return new T(); } Bar b; b = foo(b); // T is deduced to Foo, should this work? Bar b = new Bar(); mixin("b = new " ~ typeof(b).stringof ~ "();"); // This fails, the string is "Foo" Just thinking about this has made me change my position. Accessibility raising aliases should not be allowed. It's a minefield.
Jan 24 2012
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Peter Alexander" <peter.alexander.au gmail.com> wrote in message 
news:jzvidktaqmkptrooimvt dfeed.kimsufi.thecybershadow.net...
 On Wednesday, 25 January 2012 at 00:08:25 UTC, Timon Gehr wrote:
 Accessibility-raising aliases are trivially safe, because the alias 
 declaration must have access to the aliased symbol.
You are probably right about not introducing holes, but I can imagine this getting tricky, and perhaps confusing in some cases. Here are some off the top of my head. module A; private class Foo {} public alias Foo Bar; In other modules that import A: Bar b = new typeof(b)(); // typeof(b) is Foo. Is this allowed? T foo(T)(T x) { return new T(); } Bar b; b = foo(b); // T is deduced to Foo, should this work? Bar b = new Bar(); mixin("b = new " ~ typeof(b).stringof ~ "();"); // This fails, the string is "Foo"
In all the above, the type *should* be Bar, not Foo (although it might not currently be - I'd consider that something that needs to be changed). Bar should refer to Foo *behind the scenes*, and as such, the fact that it refers to something else behind the scenes is totally irrelevent. This would also seem to be related to issue of error messages currently referring to the underlying type insted of the aliased type (which I'm convinced is the wrong way round).
 Just thinking about this has made me change my position. Accessibility 
 raising aliases should not be allowed. It's a minefield.
The issue is not with aliases, accessability already has a natural grey area: ==================== module lib; private struct Foo {} // Should any of these be allowed? public Foo getFoo() { return Foo(); } public void takeFoo(Foo f) {} struct Bar { Foo f; } ------ module main; import lib; getFoo(); // Allowed? takeFoo(getFoo()); // Allowed? Bar b; // Allowed? takeFoo(b.f); // Allowed? b.f = getFoo(); // Allowed? // Allowed? If so, can you *do* anything with x? auto x = getFoo(); ====================
Jan 24 2012
parent "Martin Nowak" <dawg dawgfoto.de> writes:
 The issue is not with aliases, accessability already has a natural grey
 area:

 ====================
 module lib;

 private struct Foo {}

 // Should any of these be allowed?
 public Foo getFoo() { return Foo(); }
 public void takeFoo(Foo f) {}
 struct Bar
 {
     Foo f;
 }

 ------

 module main;
 import lib;

 getFoo();  // Allowed?

 takeFoo(getFoo());  // Allowed?

 Bar b;  // Allowed?

 takeFoo(b.f);   // Allowed?

 b.f = getFoo();   // Allowed?

 // Allowed? If so, can you *do* anything with x?
 auto x = getFoo();

 ====================
The solution seems to be to check protection only during symbol lookup. Thus all of the above are allowed and you can do with x what Foo allows you to (aggregates default to public protection).
Jan 26 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/25/2012 01:59 AM, Peter Alexander wrote:
 On Wednesday, 25 January 2012 at 00:08:25 UTC, Timon Gehr wrote:
 Accessibility-raising aliases are trivially safe, because the alias
 declaration must have access to the aliased symbol.
You are probably right about not introducing holes, but I can imagine this getting tricky, and perhaps confusing in some cases. Here are some off the top of my head. module A; private class Foo {} public alias Foo Bar; In other modules that import A: Bar b = new typeof(b)(); // typeof(b) is Foo. Is this allowed? T foo(T)(T x) { return new T(); } Bar b; b = foo(b); // T is deduced to Foo, should this work? Bar b = new Bar(); mixin("b = new " ~ typeof(b).stringof ~ "();"); // This fails, the string is "Foo" Just thinking about this has made me change my position. Accessibility raising aliases should not be allowed. It's a minefield.
That is a valid counter-argument. While I am sure these issues could be sorted out, it would probably amount to over-engineering. This is basically the only useful use case worth considering: private template Tmpl(T){...} public alias Tmpl!int foo; Tmpl and Tmpl!int are two _distinct symbols_, and there is no dedicated syntax to make just one of them accessible. Therefore, this use case could be allowed as a special case: Explicit use of Tmpl from another module would be forbidden, but the instance Tmpl!int would be public under the name foo. (While explicitly instantiating Tmpl!int would fail, because Tmpl is not accessible (or ideally not visible).) There would be no public/private aliasing, and therefore all the issues you mentioned would not exist in this case.
Jan 24 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:jfnlpu$k0p$1 digitalmars.com...
 On 01/25/2012 01:59 AM, Peter Alexander wrote:
 On Wednesday, 25 January 2012 at 00:08:25 UTC, Timon Gehr wrote:
 Accessibility-raising aliases are trivially safe, because the alias
 declaration must have access to the aliased symbol.
You are probably right about not introducing holes, but I can imagine this getting tricky, and perhaps confusing in some cases. Here are some off the top of my head. module A; private class Foo {} public alias Foo Bar; In other modules that import A: Bar b = new typeof(b)(); // typeof(b) is Foo. Is this allowed? T foo(T)(T x) { return new T(); } Bar b; b = foo(b); // T is deduced to Foo, should this work? Bar b = new Bar(); mixin("b = new " ~ typeof(b).stringof ~ "();"); // This fails, the string is "Foo" Just thinking about this has made me change my position. Accessibility raising aliases should not be allowed. It's a minefield.
That is a valid counter-argument. While I am sure these issues could be sorted out, it would probably amount to over-engineering. This is basically the only useful use case worth considering: private template Tmpl(T){...} public alias Tmpl!int foo; Tmpl and Tmpl!int are two _distinct symbols_, and there is no dedicated syntax to make just one of them accessible. Therefore, this use case could be allowed as a special case: Explicit use of Tmpl from another module would be forbidden, but the instance Tmpl!int would be public under the name foo. (While explicitly instantiating Tmpl!int would fail, because Tmpl is not accessible (or ideally not visible).) There would be no public/private aliasing, and therefore all the issues you mentioned would not exist in this case.
There's no need for special cases. Just don't go de-aliasing symbols. That takes care of everything.
Jan 24 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/25/2012 03:56 AM, Nick Sabalausky wrote:
 "Timon Gehr"<timon.gehr gmx.ch>  wrote in message
 news:jfnlpu$k0p$1 digitalmars.com...
 On 01/25/2012 01:59 AM, Peter Alexander wrote:
 On Wednesday, 25 January 2012 at 00:08:25 UTC, Timon Gehr wrote:
 Accessibility-raising aliases are trivially safe, because the alias
 declaration must have access to the aliased symbol.
You are probably right about not introducing holes, but I can imagine this getting tricky, and perhaps confusing in some cases. Here are some off the top of my head. module A; private class Foo {} public alias Foo Bar; In other modules that import A: Bar b = new typeof(b)(); // typeof(b) is Foo. Is this allowed? T foo(T)(T x) { return new T(); } Bar b; b = foo(b); // T is deduced to Foo, should this work? Bar b = new Bar(); mixin("b = new " ~ typeof(b).stringof ~ "();"); // This fails, the string is "Foo" Just thinking about this has made me change my position. Accessibility raising aliases should not be allowed. It's a minefield.
That is a valid counter-argument. While I am sure these issues could be sorted out, it would probably amount to over-engineering. This is basically the only useful use case worth considering: private template Tmpl(T){...} public alias Tmpl!int foo; Tmpl and Tmpl!int are two _distinct symbols_, and there is no dedicated syntax to make just one of them accessible. Therefore, this use case could be allowed as a special case: Explicit use of Tmpl from another module would be forbidden, but the instance Tmpl!int would be public under the name foo. (While explicitly instantiating Tmpl!int would fail, because Tmpl is not accessible (or ideally not visible).) There would be no public/private aliasing, and therefore all the issues you mentioned would not exist in this case.
There's no need for special cases. Just don't go de-aliasing symbols. That takes care of everything.
It does not. private class A{ static A factory(); } public alias A B; What is typeof(B.factory()) ?
Jan 24 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:jfnsne$10re$1 digitalmars.com...
 On 01/25/2012 03:56 AM, Nick Sabalausky wrote:
 There's no need for special cases. Just don't go de-aliasing symbols. 
 That
 takes care of everything.
It does not. private class A{ static A factory(); } public alias A B; What is typeof(B.factory()) ?
That's not a problem that's specific to alias. It's symptomatic of a more general access issue (instances of private types exposed in a public interface) that is *not* solved by prohibiting access-expanding aliases: private class A{ static A factory(); } public class B{ A foo() { return A.factory(); } } In another module: typeof((new B()).foo()) // What should happen? If "public alias A B" must be banned due to tough accessibility questions, then so must "class B". Point is, it's not an issue specific to alias.
Jan 24 2012
parent "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:jfo1i0$18rq$1 digitalmars.com...
 "Timon Gehr" <timon.gehr gmx.ch> wrote in message 
 news:jfnsne$10re$1 digitalmars.com...
 On 01/25/2012 03:56 AM, Nick Sabalausky wrote:
 There's no need for special cases. Just don't go de-aliasing symbols. 
 That
 takes care of everything.
It does not. private class A{ static A factory(); } public alias A B; What is typeof(B.factory()) ?
That's not a problem that's specific to alias. It's symptomatic of a more general access issue (instances of private types exposed in a public interface) that is *not* solved by prohibiting access-expanding aliases: private class A{ static A factory(); } public class B{ A foo() { return A.factory(); } } In another module: typeof((new B()).foo()) // What should happen? If "public alias A B" must be banned due to tough accessibility questions, then so must "class B". Point is, it's not an issue specific to alias.
Of course, my position isn't purely defensive. Here's why access-expanding aliases cannot be prohibited: private struct DirtyFooImpl(int i){} template Foo { alias DirtyFooImpl!5 Foo; } That's a simplistic example of very common, very useful idiom. Note that there's no way to do that without access-expanding aliases. If access-expanding aliases are banned, then this idiom must go away too. Then, a big chunk of my Goldie project and no doubt many other projects suddenly break, and the only way around it is to publically expose things that are *not supposed to be exposed*, and congrats, now we've just stepped back in time to pre-encapsulation-enforcement days.
Jan 24 2012
prev sibling parent reply =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <ludwig informatik.uni-luebeck.de> writes:
Another example would be synchronized classes:

synchronized class X {
	public alias f g;
	private void f(){}
}

Now g() would be a public method that is not protected by the class' 
mutex. This case would have to be explicitly forbidden.
Jan 25 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Sönke Ludwig" <ludwig informatik.uni-luebeck.de> wrote in message 
news:jfoh1s$25ce$1 digitalmars.com...
 Another example would be synchronized classes:

 synchronized class X {
 public alias f g;
 private void f(){}
 }

 Now g() would be a public method that is not protected by the class' 
 mutex. This case would have to be explicitly forbidden.
Or just cause f to be protected by the class's mutex.
Jan 25 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:jfojur$2a7l$1 digitalmars.com...
 "Sönke Ludwig" <ludwig informatik.uni-luebeck.de> wrote in message 
 news:jfoh1s$25ce$1 digitalmars.com...
 Another example would be synchronized classes:

 synchronized class X {
 public alias f g;
 private void f(){}
 }

 Now g() would be a public method that is not protected by the class' 
 mutex. This case would have to be explicitly forbidden.
Or just cause f to be protected by the class's mutex.
After all, if you're making a public alias of f, then you obviously *do* want that function to be public-accessible, just not through the *name* "f".
Jan 25 2012
parent =?ISO-8859-15?Q?S=F6nke_Ludwig?= <ludwig informatik.uni-luebeck.de> writes:
Am 25.01.2012 11:02, schrieb Nick Sabalausky:
 "Nick Sabalausky"<a a.a>  wrote in message
 news:jfojur$2a7l$1 digitalmars.com...
 "Sönke Ludwig"<ludwig informatik.uni-luebeck.de>  wrote in message
 news:jfoh1s$25ce$1 digitalmars.com...
 Another example would be synchronized classes:

 synchronized class X {
 public alias f g;
 private void f(){}
 }

 Now g() would be a public method that is not protected by the class'
 mutex. This case would have to be explicitly forbidden.
Or just cause f to be protected by the class's mutex.
After all, if you're making a public alias of f, then you obviously *do* want that function to be public-accessible, just not through the *name* "f".
...although it would be a bit awkward to have the original function change just because it is aliased somewhere (a bit like Schrödinger's cat). But actually I realize that there are far worse things concerning shared/synchronized + classes, so my example maybe is not really specific to 'alias' (e.g. I'm not sure what happens now if you make a delegate of f()...)
Jan 25 2012
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"Peter Alexander" <peter.alexander.au gmail.com> wrote in message 
news:bfhygfbdlubuwelaqfws dfeed.kimsufi.thecybershadow.net...
 For example, one could argue that it's also obvious that an alias should 
 behave exactly the same as the thing it aliases. Allowing aliases to 
 change protection would break that.
FWIW, If someone were to argue that, my response would be something like: 1. If you wanted it *exactly* the same, you wouldn't have aliased it at all. So naturally, that "exactly" is subject to reasonable exceptions. 2. Protection levels apply to symbols, not the construct or data the symbol refers to. 3. (Just reiterating I guess:) Protection levels are not, should not, and cannot realistically be transitive.
 For the record, I agree that the answer should be "yes", but it's
Jan 24 2012
prev sibling parent reply equinox atw.hu writes:
Hi,

I have been thinking . Would not C and C++ backend would make DMD more  =

versatile?
D language could be used in many platforms easily.
D language could be used in .net and elsewhere.
It could be compiled with other language that are also translated into  =

C/C++.

Regards

M=E1rton Papp
Jan 25 2012
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
<equinox atw.hu> wrote in message news:op.v8mxx6s9xa30qa marton-pc...
Hi,

I have been thinking . Would not C and C++ backend would make DMD more 
versatile?
D language could be used in many platforms easily.
D language could be used in .net and elsewhere.
It could be compiled with other language that are also translated into 
C/C++.
I think LDC can do that...At least in theory anyway, since LLVM has a C backend.
Jan 25 2012
parent "Bernard Helyer" <b.helyer gmail.com> writes:
On Wednesday, 25 January 2012 at 12:03:15 UTC, Nick Sabalausky 
wrote:
 <equinox atw.hu> wrote in message 
 news:op.v8mxx6s9xa30qa marton-pc...
Hi,

I have been thinking . Would not C and C++ backend would make 
DMD more versatile?
D language could be used in many platforms easily.
D language could be used in .net and elsewhere.
It could be compiled with other language that are also 
translated into C/C++.
I think LDC can do that...At least in theory anyway, since LLVM has a C backend.
It does, but they tell you not to use it. Make of that what you will.
Jan 25 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 25 Jan 2012 05:26:20 -0500, <equinox atw.hu> wrote:

 Hi,

 I have been thinking . Would not C and C++ backend would make DMD more  
 versatile?
 D language could be used in many platforms easily.
 D language could be used in .net and elsewhere.
 It could be compiled with other language that are also translated into  
 C/C++.
IIRC, Walter is (slowly) working on that. -Steve
Jan 25 2012
prev sibling parent Andrew Wiley <wiley.andrew.j gmail.com> writes:
On Wed, Jan 25, 2012 at 4:26 AM,  <equinox atw.hu> wrote:
 Hi,

 I have been thinking . Would not C and C++ backend would make DMD more
 versatile?
 D language could be used in many platforms easily.
 D language could be used in .net and elsewhere.
 It could be compiled with other language that are also translated into
 C/C++.
As far as platform support goes, GDC *should* be able to target pretty much any platform GCC can currently target. There are probably some platform-specific issues at this point; one example would be that you have to disable the section-anchors optimization to get D running on ARM. There are also some fun things like Fibers not working because the getcontext/setcontext/makecontext functions in glibc are just stubs on ARM, but Iain has done an excellent job of adding GCC-specific version blocks to Druntime that replace most of the platform-specific code with pre-written GCC intrinsics. I know Daniel Green had some difficulty getting a toolchain that supports TLS on Windows, hopefully he can chime in on whether that's just Windows or will be an issue on other platforms as well.
Jan 25 2012