Jump to page: 1 2
Thread overview
alias this private?
Dec 09, 2012
js.mdnq
Dec 09, 2012
Ali Çehreli
Dec 09, 2012
js.mdnq
Dec 09, 2012
js.mdnq
Dec 09, 2012
Ali Çehreli
Dec 09, 2012
js.mdnq
Dec 09, 2012
Ali Çehreli
Dec 09, 2012
js.mdnq
Dec 10, 2012
Ali Çehreli
Dec 10, 2012
js.mdnq
Dec 10, 2012
Ali Çehreli
Dec 10, 2012
js.mdnq
Dec 10, 2012
Ali Çehreli
December 09, 2012
Can it not be possible to use alias this on a private field?

struct Q
   private:
      int _x;
   public:
      alias _x this;

?

Seems to me that one does not always want the user to access the internal value that is aliased ;/


Q q;

q._x // error yet q, for all practical purposes is _x, we just stop the user from being able to directly access it.

For example, maybe I want to override opAssign on an int. The user can get around it by doing q._x. Seems like a bad idea.


December 09, 2012
On 12/08/2012 11:05 PM, js.mdnq wrote:
> Can it not be possible to use alias this on a private field?

I've just tested it. It is possible with dmd 2.060:

struct Q
{
private:
    int _x;
public:
    alias _x this;
}

void main()
{
    auto q = Q();
    q = 42;
    assert(q._x == 42);
}

> struct Q
> private:
> int _x;
> public:
> alias _x this;
>
> ?
>
> Seems to me that one does not always want the user to access the
> internal value that is aliased ;/

Then the programmer should not "alias this" that member.

> Q q;
>
> q._x // error yet q, for all practical purposes is _x,

q is for /some/ practical purposes is _x. :)

> we just stop the
> user from being able to directly access it.

That is the case, because the member is private.

> For example, maybe I want to override opAssign on an int.

Sorry, I could not understand that.

> The user can
> get around it by doing q._x. Seems like a bad idea.

The user can't do that because _x is private. If they can, then it must be a bug. One thing that is confusing in D is that private members of a type are accessible by the module that includes that type. Is that the question?

Ali

December 09, 2012
On Sunday, 9 December 2012 at 08:27:45 UTC, Ali Çehreli wrote:
> On 12/08/2012 11:05 PM, js.mdnq wrote:
> > Can it not be possible to use alias this on a private field?
>
> I've just tested it. It is possible with dmd 2.060:
>
> struct Q
> {
> private:
>     int _x;
> public:
>     alias _x this;
> }
>
> void main()
> {
>     auto q = Q();
>     q = 42;
>     assert(q._x == 42);
> }
>
> > struct Q
> > private:
> > int _x;
> > public:
> > alias _x this;
> >
> > ?
> >
> > Seems to me that one does not always want the user to access
> the
> > internal value that is aliased ;/
>
> Then the programmer should not "alias this" that member.
>
> > Q q;
> >
> > q._x // error yet q, for all practical purposes is _x,
>
> q is for /some/ practical purposes is _x. :)
>
> > we just stop the
> > user from being able to directly access it.
>
> That is the case, because the member is private.
>
> > For example, maybe I want to override opAssign on an int.
>
> Sorry, I could not understand that.
>
> > The user can
> > get around it by doing q._x. Seems like a bad idea.
>
> The user can't do that because _x is private. If they can, then it must be a bug. One thing that is confusing in D is that private members of a type are accessible by the module that includes that type. Is that the question?
>
> Ali

No, it doens't work on my version of D(2.058 I think). So maybe ok now.
December 09, 2012
Actually, it doesn't seem to work ;/ Your code worked but mine does unless I make it public. It is a public/private issue and I get a ton of errors:


module main;

import std.stdio;



class A
{
	public:
		string Name;

		struct B(T)
		{
			private:
			//public:
				T Value;
			public:
				alias Value this;

				T opAssign(F)(F v)
				{
					//writeln(Name ~ " ...");
					Value = cast(T)v;
					return Value;
				}
	
		}
	
		B!int b;
}


int main(string[] argv)
{

	A c = new A();

	c.b = 34;
	writeln(c.b);
	getchar();
	return 0;
}


Error: template std.conv.toImpl does not match any function template declaration
Error: template std.conv.toImpl cannot deduce template function from argument types !(int)(B!(int))
Error: template instance toImpl!(int) errors instantiating template
Error: template instance std.conv.to!(int).to!(B!(int)) error instantiating

So while it might "work" in the simple case it doesn't seem to actually work...
December 09, 2012
On 12/09/2012 01:42 AM, js.mdnq wrote:

> Actually, it doesn't seem to work ;/ Your code worked but mine does
> unless I make it public. It is a public/private issue and I get a ton of
> errors:

This is not adding to the discussion much but it is again because the member is private. writeln() is in a separate module, which cannot access a private member of another module. (Actually it is std.traits.isImplicitlyConvertible that can't access that member.):

class A
{
    struct B(T)
    {
    private:
        //public:
        T Value;
    public:
        alias Value this;

        T opAssign(F)(F v)
        {
            //writeln(Name ~ " ...");
            Value = cast(T)v;
            return Value;
        }
    }

    B!int b;
}

// Copied from isImplicitlyConvertible
template isImplicitlyConvertible_LOCAL(From, To)
{
    enum bool isImplicitlyConvertible_LOCAL = is(typeof({
        void fun(ref From v)
        {
            void gun(To) {}
            gun(v);
        }
    }));
}

import std.traits;

int main(string[] argv)
{

    A c = new A();

    c.b = 34;

    static assert(isImplicitlyConvertible_LOCAL!(A.B!int, int)); // PASSES
    static assert(isImplicitlyConvertible      !(A.B!int, int)); // FAILS

    return 0;
}

> So while it might "work" in the simple case it doesn't seem to actually
> work...

I am not sure that it should work. If it is private, maybe it should stay private.

What you seem to need is read-only access to a private member. There are other ways of achieving that. The following program uses both a read-only property function and an 'alias this':

module main;

import std.stdio;

class A
{
    struct B(T)
    {
    private:
        //public:
        T Value_;
    public:

        // read-only accessor
        T Value() const @property
        {
            return Value_;
        }

        // Automatic conversion to the read-only accessor
        alias Value this;

        T opAssign(F)(F v)
        {
            //writeln(Name ~ " ...");
            Value_ = cast(T)v;
            return Value_;
        }
    }

    B!int b;
}

int main(string[] argv)
{

    A c = new A();

    c.b = 34;
    writeln(c.b);
    getchar();
    return 0;
}

Ali

December 09, 2012
On Sunday, 9 December 2012 at 16:50:55 UTC, Ali Çehreli wrote:
> On 12/09/2012 01:42 AM, js.mdnq wrote:
>
> > Actually, it doesn't seem to work ;/ Your code worked but
> mine does
> > unless I make it public. It is a public/private issue and I
> get a ton of
> > errors:
>
> This is not adding to the discussion much but it is again because the member is private. writeln() is in a separate module, which cannot access a private member of another module. (Actually it is std.traits.isImplicitlyConvertible that can't access that member.):
>
> class A
> {
>     struct B(T)
>     {
>     private:
>         //public:
>         T Value;
>     public:
>         alias Value this;
>
>         T opAssign(F)(F v)
>         {
>             //writeln(Name ~ " ...");
>             Value = cast(T)v;
>             return Value;
>         }
>     }
>
>     B!int b;
> }
>
> // Copied from isImplicitlyConvertible
> template isImplicitlyConvertible_LOCAL(From, To)
> {
>     enum bool isImplicitlyConvertible_LOCAL = is(typeof({
>         void fun(ref From v)
>         {
>             void gun(To) {}
>             gun(v);
>         }
>     }));
> }
>
> import std.traits;
>
> int main(string[] argv)
> {
>
>     A c = new A();
>
>     c.b = 34;
>
>     static assert(isImplicitlyConvertible_LOCAL!(A.B!int, int)); // PASSES
>     static assert(isImplicitlyConvertible      !(A.B!int, int)); // FAILS
>
>     return 0;
> }
>
> > So while it might "work" in the simple case it doesn't seem
> to actually
> > work...
>
> I am not sure that it should work. If it is private, maybe it should stay private.
>
> What you seem to need is read-only access to a private member. There are other ways of achieving that. The following program uses both a read-only property function and an 'alias this':
>
> module main;
>
> import std.stdio;
>
> class A
> {
>     struct B(T)
>     {
>     private:
>         //public:
>         T Value_;
>     public:
>
>         // read-only accessor
>         T Value() const @property
>         {
>             return Value_;
>         }
>
>         // Automatic conversion to the read-only accessor
>         alias Value this;
>
>         T opAssign(F)(F v)
>         {
>             //writeln(Name ~ " ...");
>             Value_ = cast(T)v;
>             return Value_;
>         }
>     }
>
>     B!int b;
> }
>
> int main(string[] argv)
> {
>
>     A c = new A();
>
>     c.b = 34;
>     writeln(c.b);
>     getchar();
>     return 0;
> }
>
> Ali

but b is not private, only the internal representation of it. e.g., `alias Value_ this` is public. I do realize that it sort of makes Value_ and b one and the same but they are not quite the same.

To me, it breaks encapsulation. writeln(c.b) is accessing b, not Value_. b is a "virtual type" in the sense that it wraps Value_. While it seems to do something funky like change the protection of Value_ from private to public it doesn't. There is no way to access Value_ when it is private. i.e., we can't do c.b.Value_;

To drive the point home. We could/should be able to completely encapsulate `Value_` by overriding opAssign and add getters and setters so that `Value_` is actually never even used(although pointless then).

Another way to see this:

struct sPassword
{
    private:
        string Password;
    public:
        alias this Password;
        opAssign
        opCast
        opCmp
        opGet { return "******"; }
        Change(old pass, new pass) { if ... }
        Validate(pass) { pass == Password; ... }
}

sPassword myPass;
writeln(myPass) same as writeln(myPass.Get()) which prints ******

Such a type would be very secure. There is no way to get at Password(except through looking directly at memory, but we could encrypt it to make it difficult). But for all practical purposes myPass acts like a password.

We can't accidently display the password to the user(in fact, there is no way unless a method is added to return the password, in which case there is no reason to make Password private.

In any case, it just seems to me that we should be able to use private this way. If we want the additional functionality we just make it public.

(it does sort of seem sPassword is like a readonly type but it's more than that as it encapsulates completely)

Now, if Password was public instead of private, anyone could do myPass.Password to get the password.


(the code isn't meant to be working D code but just a mix of pseudo and hypothetical D code)
December 09, 2012
On 12/09/2012 11:23 AM, js.mdnq wrote:

> but b is not private, only the internal representation of it. e.g.,
> `alias Value_ this` is public. I do realize that it sort of makes Value_
> and b one and the same but they are not quite the same.
>
> To me, it breaks encapsulation. writeln(c.b) is accessing b, not Value_.
> b is a "virtual type" in the sense that it wraps Value_. While it seems
> to do something funky like change the protection of Value_ from private
> to public it doesn't. There is no way to access Value_ when it is
> private. i.e., we can't do c.b.Value_;

That's great. Value_ must remain private.

> To drive the point home. We could/should be able to completely
> encapsulate `Value_` by overriding opAssign and add getters and setters
> so that `Value_` is actually never even used(although pointless then).

That is possible in D.

> Another way to see this:
>
> struct sPassword
> {
> private:
> string Password;
> public:
> alias this Password;
> opAssign
> opCast
> opCmp
> opGet { return "******"; }
> Change(old pass, new pass) { if ... }
> Validate(pass) { pass == Password; ... }
> }
>
> sPassword myPass;
> writeln(myPass) same as writeln(myPass.Get()) which prints ******

You may have a point but at least I need to see how the existing features of D are not acceptable. The following already does what you want:

struct sPassword
{
private:
    string Password_;

public:

    alias opGet this;

    string opGet() { return "******"; }
}

void main()
{
    sPassword myPass;
    assert(myPass == "******");
}

(Aside: Although its name may suggest so, opGet is not an operator function.)

> In any case, it just seems to me that we should be able to use private
> this way. If we want the additional functionality we just make it public.

Yes, private it good.

> (it does sort of seem sPassword is like a readonly type but it's more
> than that as it encapsulates completely)
>
> Now, if Password was public instead of private, anyone could do
> myPass.Password to get the password.

Yeah, not a good idea.

Ali

December 09, 2012
On Sunday, 9 December 2012 at 19:38:28 UTC, Ali Çehreli wrote:
> On 12/09/2012 11:23 AM, js.mdnq wrote:
>
> > but b is not private, only the internal representation of it.
> e.g.,
> > `alias Value_ this` is public. I do realize that it sort of
> makes Value_
> > and b one and the same but they are not quite the same.
> >
> > To me, it breaks encapsulation. writeln(c.b) is accessing b,
> not Value_.
> > b is a "virtual type" in the sense that it wraps Value_.
> While it seems
> > to do something funky like change the protection of Value_
> from private
> > to public it doesn't. There is no way to access Value_ when
> it is
> > private. i.e., we can't do c.b.Value_;
>
> That's great. Value_ must remain private.
>
> > To drive the point home. We could/should be able to completely
> > encapsulate `Value_` by overriding opAssign and add getters
> and setters
> > so that `Value_` is actually never even used(although
> pointless then).
>
> That is possible in D.
>
> > Another way to see this:
> >
> > struct sPassword
> > {
> > private:
> > string Password;
> > public:
> > alias this Password;
> > opAssign
> > opCast
> > opCmp
> > opGet { return "******"; }
> > Change(old pass, new pass) { if ... }
> > Validate(pass) { pass == Password; ... }
> > }
> >
> > sPassword myPass;
> > writeln(myPass) same as writeln(myPass.Get()) which prints
> ******
>
> You may have a point but at least I need to see how the existing features of D are not acceptable. The following already does what you want:
>
> struct sPassword
> {
> private:
>     string Password_;
>
> public:
>
>     alias opGet this;
>
>     string opGet() { return "******"; }
> }
>
> void main()
> {
>     sPassword myPass;
>     assert(myPass == "******");
> }
>
> (Aside: Although its name may suggest so, opGet is not an operator function.)
>
> > In any case, it just seems to me that we should be able to
> use private
> > this way. If we want the additional functionality we just
> make it public.
>
> Yes, private it good.
>
> > (it does sort of seem sPassword is like a readonly type but
> it's more
> > than that as it encapsulates completely)
> >
> > Now, if Password was public instead of private, anyone could
> do
> > myPass.Password to get the password.
>
> Yeah, not a good idea.
>
> Ali

Well, I would not say they are exactly the same. In your case you are aliasing on opGet while I'm talking about aliasing on the struct itself. e.g., there might be other members you do want the user to have access too. With your's, they won't be able to access them(your's is actually more restrictive).

For example, how can they access a "Validate" method like I have using your struct?



December 10, 2012
On 12/09/2012 11:52 AM, js.mdnq wrote:

> Well, I would not say they are exactly the same.

Do they have to be exactly the same? You are showing a method that fails to satisfy a requirement, I show another method which according to fail to satisfy another requirement. Software is engineering as well. What is the problem? Let's just solve it.

> In your case you are
> aliasing on opGet while I'm talking about aliasing on the struct itself.

I know.

> e.g., there might be other members you do want the user to have access
> too.

Then I give access to those members.

> With your's, they won't be able to access them(your's is actually
> more restrictive).

I don't see that.

> For example, how can they access a "Validate" method like I have using
> your struct?

It is so trivial that I am beginning to think I have not understood a tiny bit of what you have been saying, but here it goes: :)

struct sPassword
{
private:
    string Password_;

public:

    alias opGet this;

    void opAssign(string value)
    {
        Password_ = value;
    }

    string opGet() { return "******"; }

    bool Validate(string pass) { return pass == Password_; }
}

void main()
{
    sPassword myPass;
    myPass = "hello";
    assert(myPass == "******");
    assert(myPass.Validate("hello"));    // <-- here
}

I hope others can show me what I've been misunderstanding. :-/

Ali

December 10, 2012
On Monday, 10 December 2012 at 04:50:17 UTC, Ali Çehreli wrote:
> On 12/09/2012 11:52 AM, js.mdnq wrote:
>
> > Well, I would not say they are exactly the same.
>
> Do they have to be exactly the same? You are showing a method that fails to satisfy a requirement, I show another method which according to fail to satisfy another requirement. Software is engineering as well. What is the problem? Let's just solve it.
>
> > In your case you are
> > aliasing on opGet while I'm talking about aliasing on the
> struct itself.
>
> I know.
>
> > e.g., there might be other members you do want the user to
> have access
> > too.
>
> Then I give access to those members.
>
> > With your's, they won't be able to access them(your's is
> actually
> > more restrictive).
>
> I don't see that.
>
> > For example, how can they access a "Validate" method like I
> have using
> > your struct?
>
> It is so trivial that I am beginning to think I have not understood a tiny bit of what you have been saying, but here it goes: :)
>
> struct sPassword
> {
> private:
>     string Password_;
>
> public:
>
>     alias opGet this;
>
>     void opAssign(string value)
>     {
>         Password_ = value;
>     }
>
>     string opGet() { return "******"; }
>
>     bool Validate(string pass) { return pass == Password_; }
> }
>
> void main()
> {
>     sPassword myPass;
>     myPass = "hello";
>     assert(myPass == "******");
>     assert(myPass.Validate("hello"));    // <-- here
> }
>
> I hope others can show me what I've been misunderstanding. :-/
>
> Ali

Na, it seems that my lack of knowing D is at fault. I thought when you did alias this it essentially rewrote the object as the type... it seems that is not the case, at least, in what you have shown. Maybe it simply due to using opGet, which I did not know about until you brought it up?

I thought `alias this` essentially treats the object as the alias.

struct A {
    alias value this;
    int value;
    void func();
}

A a;

then a is essentially the same as a.value?  a.func() would be a.value.func() which makes no sense? At least that is how I thought alias this worked? (it's obviously more complex than what I thought)

(I'm new to D so you'll have to forgive all the stupid questions ;) D seems quite powerful and many useful ways to do things but I still haven't wrapped my head around all the intricacies)





« First   ‹ Prev
1 2