Jump to page: 1 2 3
Thread overview
Very hacky solution to class private members
Jun 09, 2022
bauss
Jun 09, 2022
bauss
Jun 09, 2022
forkit
Jun 09, 2022
bauss
Jun 09, 2022
zjh
Jun 09, 2022
zjh
Jun 09, 2022
Dom Disc
Jun 09, 2022
Dom Disc
Jun 09, 2022
forkit
Jun 09, 2022
bauss
Jun 09, 2022
Mathias LANG
Jun 09, 2022
bauss
Jun 09, 2022
bauss
Jun 09, 2022
Dom Disc
Jun 09, 2022
bauss
Jun 09, 2022
Dom Disc
Jun 09, 2022
forkit
Jun 09, 2022
Prezelboss
June 09, 2022

Below is a way to actually make class private members using a modified version of the CTFE RNG demonstrated at d-idioms: https://p0nce.github.io/d-idioms/#Compile-time-RNG and some traits checking for calling function.

It's very hacky and I don't think it should be used seriously.

I was just wondering if it could be done like this and decided to do it for fun.

It only supports properties and functions.

First we need some boilerplate code:

ulong timestampToUlong(string stamp)
{
    ulong result;

    foreach_reverse(c; stamp)
    {
        result += c;
        result *= 10;
    }

    return result;
}
enum counter(T,size_t x = [__traits(allMembers, mixin(T))].length)=x;
char[] member(ulong x)
{
    char[] buf = "void[0] _X0000000000000000;".dup;
    enum mapping = "0123456789abcdef";
    foreach_reverse(i; buf.length-17 .. buf.length-1)
    {
        buf[i] = mapping[x & 0xf];
        x >>= 4;
    }
    return buf;
}

mixin template next(T)
{
    mixin(member(counter!(T)));
}

template xorShift(T,size_t x = counter!(T))
{
    static if(x == 0)
    {
        enum xorShift = timestampToUlong(__TIMESTAMP__);
    }
    else
    {
        enum y = xorShift!(T,x-1);
        enum xorShift = 0x2545_f491_4f6c_dd1dUL
            * (((y ^ (y >> 12)) ^ ((y ^ (y >> 12)) << 25))
            ^ (((y ^ (y >> 12)) ^ ((y ^ (y >> 12)) << 25)) >> 27));
    }
}

mixin template hiddenProp(T, string name, Within, string ts = to!string(xorShift!(Within)))
{
    mixin(T.stringof ~ " _hidden_" ~ ts ~ "_" ~ name ~ ";");
    mixin("private @property " ~ T.stringof ~ " " ~ name ~ "(string caller=__FUNCTION__)() if (caller.startsWith(`" ~ fullyQualifiedName!(Within) ~ "`)) {return _hidden_" ~ ts ~ "_" ~ name ~ ";}");
    mixin("private @property void " ~ name ~ "(string caller=__FUNCTION__)(" ~ T.stringof ~ " value) if (caller.startsWith(`" ~ fullyQualifiedName!(Within) ~ "`)) { _hidden_" ~ ts ~ "_" ~ name ~ " = value;}");

    mixin next!(Within);
}

mixin template hiddenFn(string name, string fnBody, string[] params = [], T = void, Within, string ts = to!string(xorShift!(Within)))
{
    mixin(T.stringof ~ " " ~ name ~ "(string caller=__FUNCTION__)(" ~ params.join(",") ~ ") if (caller.startsWith(`" ~ fullyQualifiedName!(Within) ~ "`)) { " ~ fnBody ~ " }");

    mixin next!(Within);
}

And then we have the actual code for the class etc.

public class Foo
{
    mixin hiddenProp!(int, "x", typeof(this));
    mixin hiddenProp!(int, "y", typeof(this));

    mixin hiddenFn!("calc", q{
        return x * y;
    }, ["int x", "int y"], int, typeof(this));

    void test()
    {
        x = calc(20, 5); // ok
        writeln(x); // ok
    }
}

void main()
{
    auto foo = new Foo;
    foo.test(); // ok - prints 100
    //foo.x = 300; // not ok (compile time error.)
    //writeln(foo.x); // not ok (compile time error.)
    //int z = foo.calc(); // not ok (compile time error.)
    //writeln(z);
}

It's unbelievably stupid, but it works.

In theory you can cheat it by changing the caller to whatever you desire or you can attempt to guess the backing variables for the properties (although that's almost impossible.) - neither is worth the trouble.

You can't however accidentally call this from outside the class.

Anyway just wanted to have some fun, but please don't use this garbage in all seriousness.

June 09, 2022

On Thursday, 9 June 2022 at 07:24:24 UTC, bauss wrote:

>

...

Some minor modifications for the hiddenFn that allows you to pass types to a template instead of an array of the parameters.

Also allows one to use a "lambda" for the function body instead of a string. This lambda has to take the same amount of parameters that the function takes.

So now it can be done like this:

    mixin hiddenFn!("calc", (x,y){
        return x * y;
    }, Params!(int,int), int, typeof(this));

Instead of how to do it before:

    mixin hiddenFn!("calc", q{
        return x * y;
    }, ["int x", "int y"], int, typeof(this));

Boilerplate changes:

// Can't use std.algorithm.map in the mixin template, so we need some terrible function like this ...
static auto stringMap(alias p)(string[] r)
{
    string[] result = [];

    foreach (n; r) result ~= p(n);

    return result;
}

template Params(T...)
{
    enum Params = ({
        string[] result;

        static foreach(i; 0 .. T.length) {
            result ~= T[i].stringof ~ " _" ~ to!string(i);
        }

        return result;
    })();
}

mixin template hiddenFn(string name, alias fnBody, string[] params = [], T = void, Within, string ts = to!string(xorShift!(Within)))
{
    static if (is(T == void))
    {
        mixin(T.stringof ~ " " ~ name ~ "(string caller=__FUNCTION__)(" ~ params.join(",") ~ ") if (caller.startsWith(`" ~ fullyQualifiedName!(Within) ~ "`)) { fnBody(" ~ stringMap!(p => p.split(" ")[$-1])(params).join(",") ~ "); }");
    }
    else
    {
        mixin(T.stringof ~ " " ~ name ~ "(string caller=__FUNCTION__)(" ~ params.join(",") ~ ") if (caller.startsWith(`" ~ fullyQualifiedName!(Within) ~ "`)) { return fnBody(" ~ stringMap!(p => p.split(" ")[$-1])(params).join(",") ~"); }");
    }

    mixin next!(Within);
}
June 09, 2022
On Thursday, 9 June 2022 at 08:44:50 UTC, bauss wrote:
>

honestly. how is it, that a programming language can enable you to do all this amazing stuff, like that, and yet not provide an access control option (let alone an enforceable one) at the class level.

June 09, 2022
On Thursday, 9 June 2022 at 09:22:52 UTC, forkit wrote:
> On Thursday, 9 June 2022 at 08:44:50 UTC, bauss wrote:
>>
>
> honestly. how is it, that a programming language can enable you to do all this amazing stuff, like that, and yet not provide an access control option (let alone an enforceable one) at the class level.

Honestly I couldn't tell you. I think it's because people have such strong political views around here that the majority wouldn't want change, even if that change has no impact on their workflow or even their code.

The community for D is much like its GC, very conservative.
June 09, 2022
On Thursday, 9 June 2022 at 09:22:52 UTC, forkit wrote:
> On Thursday, 9 June 2022 at 08:44:50 UTC, bauss wrote:
>>
>
> honestly. how is it, that a programming language can enable you to do all this amazing stuff, like that, and yet not provide an access control option (let alone an enforceable one) at the class level.

I still don't get why class level encapsulation should be any better than module level encapsulation.
You need it to prevent some function from accidentally use things it shouldn't use, yes? Because if you _want_ to circumvent the privacy, there are always ways to do that.
But what about all the member-functions of a class, that also should not have access to some variables? (Because most of the time, private members should only be accessed by a few members that are designed to work with them). There neither private or hidden on whatever level can help you.
So, whatever you do, the only way to review a class is to simply check that all usages of a private variable are justified at the place where it is used. And that becomes easier if you have to check only one file, but if it is only used in a part of a file doesn't reduce the effort the slightest bit. Zero. No effect.
So I just can't understand why you insist on class level encapsulation. It brings no benefit at all (at least regarding the effort for reviews).
June 09, 2022

On Thursday, 9 June 2022 at 09:49:14 UTC, bauss wrote:

>

The community for D is much like its GC, very conservative.

Is stubborn!

June 09, 2022

On Thursday, 9 June 2022 at 10:05:37 UTC, zjh wrote:

>

Is stubborn!

So, many Chinese have left D!

June 09, 2022

On Thursday, 9 June 2022 at 10:03:02 UTC, Dom Disc wrote:

>

But what about all the member-functions of a class, that also should not have access to some variables? (Because most of the time, private members should only be accessed by a few members that are designed to work with them). There neither private or hidden on whatever level can help you.

I personally use underscore for member functions or class fields that has to be handled with care.

But if you look at the D standard library you see that some modules are convoluted and in such settings it would be better with another protection level.

In general if somebody wants to improve the language then they can find many of the problem spots in the D standard library and use that for making judgments.

If someone ever started on D3, that is the place to start IMO.

June 09, 2022

On Thursday, 9 June 2022 at 10:26:31 UTC, Ola Fosheim Grøstad wrote:

>

On Thursday, 9 June 2022 at 10:03:02 UTC, Dom Disc wrote:

>

But what about all the member-functions of a class, that also should not have access to some variables? (Because most of the time, private members should only be accessed by a few members that are designed to work with them). There neither private or hidden on whatever level can help you.

I personally use underscore for member functions or class fields that has to be handled with care.

Whatever you do, it needs to be something human-readable, because the compiler can't help you there.

>

But if you look at the D standard library you see that some modules are convoluted and in such settings it would be better with another protection level.

No.
If something is convoluted, you need to sort it out and split into two modules. Another protection level won't help. Because, as I said, a new level won't reduce your effort to understand whats happening, you still need to inspect everything within the file. But splitting would help a lot with that.

>

In general if somebody wants to improve the language then they can find many of the problem spots in the D standard library and use that for making judgments.

Jup. But new privacy-levels are no solution to them.

>

If someone ever started on D3, that is the place to start IMO.

Sorting things out should be possible without need for an new fork. It should be done withing the actual phobos as it wouldn't change the interface (at least not much).

June 09, 2022
On Thursday, 9 June 2022 at 10:03:02 UTC, Dom Disc wrote:
> On Thursday, 9 June 2022 at 09:22:52 UTC, forkit wrote:
>> On Thursday, 9 June 2022 at 08:44:50 UTC, bauss wrote:
>>>
>>
>> honestly. how is it, that a programming language can enable you to do all this amazing stuff, like that, and yet not provide an access control option (let alone an enforceable one) at the class level.
>
> I still don't get why class level encapsulation should be any better than module level encapsulation.
> You need it to prevent some function from accidentally use things it shouldn't use, yes? Because if you _want_ to circumvent the privacy, there are always ways to do that.
> But what about all the member-functions of a class, that also should not have access to some variables? (Because most of the time, private members should only be accessed by a few members that are designed to work with them). There neither private or hidden on whatever level can help you.
> So, whatever you do, the only way to review a class is to simply check that all usages of a private variable are justified at the place where it is used. And that becomes easier if you have to check only one file, but if it is only used in a part of a file doesn't reduce the effort the slightest bit. Zero. No effect.
> So I just can't understand why you insist on class level encapsulation. It brings no benefit at all (at least regarding the effort for reviews).

Might as well just make everything public then, right? Why stop there. Removing private, protected, package etc. is the way to go then?

I mean, you can review them all yourself and make sure they're not used incorrectly.

The flawed mentality in your answer is that you forget that the point of it all is to cut down the amount of code you have to review.

There's no reason to do the analysis yourself if the compiler can do it for you in 99% of the cases.
« First   ‹ Prev
1 2 3