March 21, 2012
On 03/20/2012 10:36 PM, deadalnix wrote:
> Even the propagation of pure, @safe, nothrow and const that has been
> discussed recently can be done with that feature.
>

I'm sceptical. How would that work exactly?

March 21, 2012
On 3/21/12 11:15 AM, F i L wrote:
> Andrei Alexandrescu wrote:
>> Is this implemented, or a thought?
>
> Just a thought (I even accidentally reversed the key-value order), but I
> don't see why it couldn't work. I'll try and make up a quick
> implementation.

Wouldn't a better approach rely on a compile-time structure instead of a hash?

Andrei

March 21, 2012
On 3/21/12 11:17 AM, Timon Gehr wrote:
> On 03/20/2012 10:36 PM, deadalnix wrote:
>> Even the propagation of pure, @safe, nothrow and const that has been
>> discussed recently can be done with that feature.
>>
>
> I'm sceptical. How would that work exactly?

I, too, am highly skeptical. For one thing these attributes must be made part of the type and have deep connections with code semantics.

Andrei
March 21, 2012
On Wednesday, 21 March 2012 at 16:21:21 UTC, Andrei Alexandrescu wrote:
> On 3/21/12 11:15 AM, F i L wrote:
>> Andrei Alexandrescu wrote:
>>> Is this implemented, or a thought?
>>
>> Just a thought (I even accidentally reversed the key-value order), but I
>> don't see why it couldn't work. I'll try and make up a quick
>> implementation.
>
> Wouldn't a better approach rely on a compile-time structure instead of a hash?

I'm not sure, you're understand of D's compiler-time structures is much better than mine. Serialization "attributes" are mostly used at runtime, so having mixing in a static enum *should* mean reflection upon the property at both runtime and compiletime.


March 21, 2012
On 2012-03-21 16:11, Andrei Alexandrescu wrote:
I think the liability here is that b needs to appear in two places, once
> in the declaration proper and then in the NonSerialized part. (A
> possible advantage is that sometimes it may be advantageous to keep all
> symbols with a specific attribute in one place.) A possibility would be
> to make the mixin expand to the field and the metadata at once.

Yes, but that just looks ugly:

class Foo
{
    int a;
    mixin NonSerialized!(int, "b");
}

That's why it's so nice with attributes.

> Did you mean
>
> static const __nonSerialized = ["b"];
>
> ?

Yes, sorry.

> In case there are several non-serialized variables, how do you avoid
> clashes between different definitions of __nonSerialized?

In my current implementation you are forced to only mixin one NonSerialized per type:

class Foo
{
    int a;
    int b;
    mixin NonSerialized!(a, b);
}

Of course there are ways around that with various pros and cons.

-- 
/Jacob Carlborg
March 21, 2012
On 2012-03-21 16:20, F i L wrote:
> Andrei Alexandrescu wrote:
>> In case there are several non-serialized variables, how do you avoid
>> clashes between different definitions of __nonSerialized?
>
> struct A {
> int a, b;
> mixin NonSerialized!(a, b);
> }
>
> static const __nonSerialized = ["a", "b"];
>

Exactly.

-- 
/Jacob Carlborg
March 21, 2012
On 2012-03-21 16:26, F i L wrote:

> Also, if where meant how could you store multiple types, you could just
> use an Associative Array:
>
> struct A {
> int a;
> float b;
> mixin NonSerialized!(a, b);
> }
>
> static const __nonSerialized = ["int":"a", "int":"b"];

Only the name of the variables are necessary in my serialization library.

-- 
/Jacob Carlborg
March 21, 2012
Jacob Carlborg wrote:
> Only the name of the variables are necessary in my serialization library.

Wouldn't mixing in an enum be more useful? You could use it at compile time that way.
March 21, 2012
On Wednesday, 21 March 2012 at 16:02:22 UTC, Andrei Alexandrescu wrote:
> Ideally the above should work, and also mixing in several NonSerialized instances within the same type should also work.


Oh god, I feel like the spawn of Hacktan.

I'm taking the DSL identifiers to the max. Consider
the following:

http://arsdnet.net/dcode/omg.d


Bottom line:

struct A {
        int a;
        int b;
        mixin Note!(a, q{ "NonSerialized" });
        mixin Note!(a, q{ "Awesome" });
        mixin Note!(b, q{ "Filthy Hack" });
}

void main() {
        pragma(msg, getNotes!(A.a));
}

$ dmd omg.d
["NotSerialized", "Awesome"]



How does it work?



What it does is for each note, it creates a dummy
enum.

The enum's name is a D expression, encoded as a
valid identifier. This expression is a ~= op here.

The struct looks like this:

struct A{
  int a;
  int b;
  enum _attr_mixin_a_32_4c_NonSerialized;
  enum _attr_mixin_a_32_4c_Awesome;
  enum _attr_mixin_b_32_4c_Filthy_32_Hack;
}


getNotes looks for this pattern, decodes it,
and then mixes in the expression:

string[] notes;
if(identifier is the right item)
mixin("notes " ~ decoded_identifier);

return notes;




So, it embeds D code to rebuild the requested
data as the names of identifiers.

We run it every time we want to get it.



Note that everything I said in my long post still
applies here. Like I said before, we *can* make it
work, but it comes with a lot of baggage that hurts
maintainability and interop with third party code.

Remember, you have to add code to your library just
to *ignore* these attributes.

You can't just ignore them, no, you have to add special
code to skip them.

That's no good. This also has duplicated names and the
other problems mentioned before with overloading,
inheritance and more.


The compiler keeping a list of notes attached to the
declaration remains the only *right* way to do it. That
it is slightly prettier is an added benefit, but not the
main reason why we need it there.
March 21, 2012
On Wednesday, 21 March 2012 at 17:26:19 UTC, Adam D. Ruppe wrote:
> The compiler keeping a list of notes attached to the
> declaration remains the only *right* way to do it.

Another note on correctness btw, this thing is wrong
if in other modules.


mixin Note!(a, q{ NotSerialized() });

that string loses the exact type. But, let's
say we solved that, and uses the module name
or something.


But then, what if:

module cool;

import serialization.attributes;

struct cool {
   int a;
   mixin Note!(a, serialization.attributes.amazing);
}

==

// another module
import cool;
void main() {
   getNotes!(cool.cool.a);
}


That won't compile. When it tries to mixin the note,
it will say undefinied identifier "amazing" because
the mixin is evaluated in another scope than the original
declaration.

So while module cool imported serilization.attributes,
module main or module notes (I'm not sure exactly where this
is mixed in by the time we're all said and done tbh but it
doesn't matter) has not.


Thus the mixin will fail.



I had this same problem when trying to do default arguments
in web.d by parsing stringof and mixing it in.

It works for built-in types like string and int, but
it doesn't work for user defined types, which are perfectly
valid function params (they work fine in the rest of web.d).

But the mixin scope is wrong so those types become undefined.







Again, we can get kinda close with these D tricks, but it
just cannot go all the way - and much of the interesting stuff
is behind that barrier.


The compiler can do it easily though, and get it right, enabling
us to do a lot more in the library down the line.