www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - shared and getParameterStorageClasses bug?

reply Jean-Louis Leroy <jl leroy.nyc> writes:
void foo(lazy shared Object);
pragma(msg, __traits(getParameterStorageClasses, foo, 0)); // 
tuple("lazy")

Shouldn't this return a tuple("lazy", "shared)? Given that 
`shared` is documented as a parameter storage class?
Aug 22 2020
next sibling parent Meta <jared771 gmail.com> writes:
On Saturday, 22 August 2020 at 18:34:21 UTC, Jean-Louis Leroy 
wrote:
 void foo(lazy shared Object);
 pragma(msg, __traits(getParameterStorageClasses, foo, 0)); // 
 tuple("lazy")

 Shouldn't this return a tuple("lazy", "shared)? Given that 
 `shared` is documented as a parameter storage class?
I'm not sure why the documentation says that, but I believe shared is considered a "type constructor", not a storage class. It's in the same class as const, immutable, etc.
Aug 22 2020
prev sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Saturday, 22 August 2020 at 18:34:21 UTC, Jean-Louis Leroy 
wrote:
 void foo(lazy shared Object);
 pragma(msg, __traits(getParameterStorageClasses, foo, 0)); // 
 tuple("lazy")

 Shouldn't this return a tuple("lazy", "shared)? Given that 
 `shared` is documented as a parameter storage class?
From a grammar point of view, type qualifiers (`const`, `immutable`, `inout` and `shared`) can appear as 4 different entities: 1. Type constructors [0] 2. Variable storage classes [1] 3. Parameter attributes [2] 4. Member function attributes [3] Parameter attributes grammatically include both UDAs and parameter storage classes (confusingly named `InOut` in the spec), so we can actually collapse the grammatical entities related to variables (which include parameters) to just 2 kinds: type constructors and storage classes. Semantically: Q T x; // A) storage class syntax Q(T) x; // B) type constructor syntax A) and B) are equivalent (where `Q` is some type qualifier and `T` is some type). During semantic processing the compiler erases the difference between two by converting qualifiers appearing as storage classes to type constructors (IIRC described via `mtype.d`). Which leaves `lazy`, `in`, `out`, `ref`, `return` and `scope` as the only actual parameter storage classes that you can query. (`auto ref` is resolved to either `ref` or no storage class during IFTI semantic processing). [0]: https://dlang.org/spec/grammar.html#TypeCtor [1]: https://dlang.org/spec/grammar.html#StorageClass [2]: https://dlang.org/spec/grammar.html#Parameters [3]: https://dlang.org/spec/grammar.html#MemberFunctionAttributes
Aug 22 2020
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Sunday, 23 August 2020 at 06:42:02 UTC, Petar Kirov 
[ZombineDev] wrote:

 From a grammar point of view, type qualifiers (`const`, 
 `immutable`, `inout` and `shared`) can appear as 4 different 
 entities:
 1. Type constructors [0]
 2. Variable storage classes [1]
 3. Parameter attributes [2]
 4. Member function attributes [3]

 Parameter attributes grammatically include both UDAs and 
 parameter storage classes (confusingly named `InOut` in the 
 spec), so we can actually collapse the grammatical entities
 related to variables (which include parameters) to just 2 
 kinds: type constructors and storage classes.

 Semantically:

    Q T x;  // A) storage class syntax
    Q(T) x; // B) type constructor syntax

 A) and B) are equivalent (where `Q` is some type qualifier and 
 `T` is some type).
Thanks. Then my follow-up question is: how do I retrieve the parameter type constructors? Without resorting on scanning the stringified parameter like here: enum isSharedParameter(alias fun, uint param) = Parameters!fun[param..param+1].stringof.indexOf("shared") != -1; (of course this is not robust: it would give false positives with types that contain the substring "shared"). My actual goal is to extract them in the same fashion as the storage classes, e.g.: void foo(lazy const shared Object); static assert(parameterTypeConstructors!foo == tuple("const", "shared")); Do I really have to parse a string like "(lazy shared(const(Object)))"? And, how reliable would this solution be?
Aug 23 2020
next sibling parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Sunday, 23 August 2020 at 13:44:30 UTC, Jean-Louis Leroy wrote:
 On Sunday, 23 August 2020 at 06:42:02 UTC, Petar Kirov 
 [ZombineDev] wrote:

 [...]
Thanks. Then my follow-up question is: how do I retrieve the parameter type constructors? Without resorting on scanning the stringified parameter like here: enum isSharedParameter(alias fun, uint param) = Parameters!fun[param..param+1].stringof.indexOf("shared") != -1; (of course this is not robust: it would give false positives with types that contain the substring "shared"). My actual goal is to extract them in the same fashion as the storage classes, e.g.: void foo(lazy const shared Object); static assert(parameterTypeConstructors!foo == tuple("const", "shared")); Do I really have to parse a string like "(lazy shared(const(Object)))"? And, how reliable would this solution be?
OK since the `shared` has migrated to the type, isSharedParameter can be written like this: enum isSharedParameter(alias fun, uint param) = is(Parameters!fun[param] == SharedOf!(Parameters!fun[param]));
Aug 23 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 23 August 2020 at 14:11:21 UTC, Jean-Louis Leroy wrote:
 OK since the `shared` has migrated to the type, 
 isSharedParameter can be written like this:

 enum isSharedParameter(alias fun, uint param) =
   is(Parameters!fun[param] == SharedOf!(Parameters!fun[param]));
An even simpler way is to use the pattern-matching feature of `is(...)`: enum isSharedParameter(alias fun, size_t param) = is(Parameters!fun[param] == shared(T), T); You can read this as, "there exists some T such that Parameters!fun[param] is shared(T)".
Aug 23 2020
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/23/20 10:21 AM, Paul Backus wrote:
 On Sunday, 23 August 2020 at 14:11:21 UTC, Jean-Louis Leroy wrote:
 OK since the `shared` has migrated to the type, isSharedParameter can 
 be written like this:

 enum isSharedParameter(alias fun, uint param) =
   is(Parameters!fun[param] == SharedOf!(Parameters!fun[param]));
An even simpler way is to use the pattern-matching feature of `is(...)`: enum isSharedParameter(alias fun, size_t param) =     is(Parameters!fun[param] == shared(T), T); You can read this as, "there exists some T such that Parameters!fun[param] is shared(T)".
is(Parameters!fun[param] == shared); This works for all type constructors. I think there's no way to get this as a nice string list though like a __traits might do (though it could be done). -Steve
Aug 23 2020
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/23/20 10:21 AM, Paul Backus wrote:
 On Sunday, 23 August 2020 at 14:11:21 UTC, Jean-Louis Leroy wrote:
 OK since the `shared` has migrated to the type, isSharedParameter can 
 be written like this:

 enum isSharedParameter(alias fun, uint param) =
   is(Parameters!fun[param] == SharedOf!(Parameters!fun[param]));
An even simpler way is to use the pattern-matching feature of `is(...)`: enum isSharedParameter(alias fun, size_t param) =     is(Parameters!fun[param] == shared(T), T); You can read this as, "there exists some T such that Parameters!fun[param] is shared(T)".
This would have problems if shared is combined with other qualifiers (const and my nemesis inout).
Aug 23 2020
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 23.08.20 21:15, Andrei Alexandrescu wrote:
 On 8/23/20 10:21 AM, Paul Backus wrote:
 On Sunday, 23 August 2020 at 14:11:21 UTC, Jean-Louis Leroy wrote:
 OK since the `shared` has migrated to the type, isSharedParameter can 
 be written like this:

 enum isSharedParameter(alias fun, uint param) =
   is(Parameters!fun[param] == SharedOf!(Parameters!fun[param]));
An even simpler way is to use the pattern-matching feature of `is(...)`: enum isSharedParameter(alias fun, size_t param) =      is(Parameters!fun[param] == shared(T), T); You can read this as, "there exists some T such that Parameters!fun[param] is shared(T)".
This would have problems if shared is combined with other qualifiers (const and my nemesis inout).
(Which is a compiler bug.)
Aug 24 2020
prev sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Sunday, 23 August 2020 at 13:44:30 UTC, Jean-Louis Leroy wrote:
 On Sunday, 23 August 2020 at 06:42:02 UTC, Petar Kirov 
 [ZombineDev] wrote:

 From a grammar point of view, type qualifiers (`const`, 
 `immutable`, `inout` and `shared`) can appear as 4 different 
 entities:
 1. Type constructors [0]
 2. Variable storage classes [1]
 3. Parameter attributes [2]
 4. Member function attributes [3]

 Parameter attributes grammatically include both UDAs and 
 parameter storage classes (confusingly named `InOut` in the 
 spec), so we can actually collapse the grammatical entities
 related to variables (which include parameters) to just 2 
 kinds: type constructors and storage classes.

 Semantically:

    Q T x;  // A) storage class syntax
    Q(T) x; // B) type constructor syntax

 A) and B) are equivalent (where `Q` is some type qualifier and 
 `T` is some type).
Thanks. Then my follow-up question is: how do I retrieve the parameter type constructors? Without resorting on scanning the stringified parameter like here: enum isSharedParameter(alias fun, uint param) = Parameters!fun[param..param+1].stringof.indexOf("shared") != -1; (of course this is not robust: it would give false positives with types that contain the substring "shared"). My actual goal is to extract them in the same fashion as the storage classes, e.g.: void foo(lazy const shared Object); static assert(parameterTypeConstructors!foo == tuple("const", "shared")); Do I really have to parse a string like "(lazy shared(const(Object)))"? And, how reliable would this solution be?
Hmm, why do you need to extract them in the same fashion? For use in string mixins? If you just want to create a proxy function then simply using std.traits.Parameters should do the trick. If you're writing a meta programming library, then perhaps you can consider representing function types as: 1. AliasSeq of the types 2. AliasSeq of the types 3. AliasSeq of the default values 4. AliasSeq of ints, each representing a bitset of the parameter storage classes that we're set. Or alternatively string[][]. Another way would be to create a Parameter struct template that contains the relevant information and then have an AliasSeq of Parameter types for each function type.
Aug 23 2020
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Sunday, 23 August 2020 at 21:14:38 UTC, Petar Kirov 
[ZombineDev] wrote:
 Hmm, why do you need to extract them in the same fashion? For 
 use in string mixins?
Yeah, it is related to my attempt to support all the language in my openmethods library.
 If you just want to create a proxy function then simply using 
 std.traits.Parameters should do the trick.
That's a whole can of worms ;-) I am trying to handle that as well as possible in a part of openmethods that I spun off and donated to bolts (see here https://github.com/aliak00/bolts/blob/master/source/bolts/experimental/refraction.d).
Aug 24 2020
parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Monday, 24 August 2020 at 21:01:30 UTC, Jean-Louis Leroy wrote:
 On Sunday, 23 August 2020 at 21:14:38 UTC, Petar Kirov 
 [ZombineDev] wrote:
 Hmm, why do you need to extract them in the same fashion? For 
 use in string mixins?
Yeah, it is related to my attempt to support all the language in my openmethods library.
 If you just want to create a proxy function then simply using 
 std.traits.Parameters should do the trick.
That's a whole can of worms ;-) I am trying to handle that as well as possible in a part of openmethods that I spun off and donated to bolts (see here https://github.com/aliak00/bolts/blob/master/source/bolts/experimental/refraction.d).
Interesting, so essentially, you need a good solution for your refractParameter function, right? I'll try to check the code in more detail later and think about it.
Aug 25 2020
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Tuesday, 25 August 2020 at 07:16:39 UTC, Petar Kirov 
[ZombineDev] wrote:
 Interesting, so essentially, you need a good solution for your 
 refractParameter function, right? I'll try to check the code in 
 more detail later and think about it.
Actually it already works as is: void original(lazy const Object); enum edited = refract!(original, "original") .withName("copy") .withParametersAt(0, Parameter("foo", "int")); mixin(edited.mixture); void expected(int, lazy const Object); static assert(is(typeof(&copy) == typeof(&expected))); The generated mixin is: pragma(msg, edited.mixture); // system bolts.experimental.refraction.ReturnType!(original) // copy(int foo, lazy bolts.experimental.refraction.Parameters!(original)[0] _0); (In this case, Parameters!(original)[0..1] (note the ..) would have worked as well - and it would have looker better too. I'll implement that soon.) Let's look at the function types: pragma(msg, typeof(&original).stringof); // void function(lazy const(Object)) pragma(msg, typeof(&copy).stringof); // void function(int foo, lazy const(Object) _0) system It looks like it is impossible to tell the difference between 'const object' and 'const(Object)' - the substitution happens too early. So I guess it doesn't matter...
Aug 25 2020
parent Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Tuesday, 25 August 2020 at 12:52:14 UTC, Jean-Louis Leroy 
wrote:
 On Tuesday, 25 August 2020 at 07:16:39 UTC, Petar Kirov 
 [ZombineDev] wrote:
 Interesting, so essentially, you need a good solution for your 
 refractParameter function, right? I'll try to check the code 
 in more detail later and think about it.
Actually it already works as is: void original(lazy const Object); enum edited = refract!(original, "original") .withName("copy") .withParametersAt(0, Parameter("foo", "int")); mixin(edited.mixture); void expected(int, lazy const Object); static assert(is(typeof(&copy) == typeof(&expected))); The generated mixin is: pragma(msg, edited.mixture); // system bolts.experimental.refraction.ReturnType!(original) // copy(int foo, lazy bolts.experimental.refraction.Parameters!(original)[0] _0); (In this case, Parameters!(original)[0..1] (note the ..) would have worked as well - and it would have looker better too. I'll implement that soon.) Let's look at the function types: pragma(msg, typeof(&original).stringof); // void function(lazy const(Object)) pragma(msg, typeof(&copy).stringof); // void function(int foo, lazy const(Object) _0) system
Nice!
 It looks like it is impossible to tell the difference between 
 'const object' and 'const(Object)' - the substitution happens 
 too early. So I guess it doesn't matter...
Yes, `Q T` and `Q(T)` is exactly the same type (for Q ∈ { const, immutable, shared, inout } ), so you shouldn't try to differentiate between the two. (And `Q(T)` is the canonical notation.) BTW, 2-3 years ago I played with a similar task (meta programming utility library), and one difference in the approach I took was to avoid thick abstractions. In some cases, this works well, though since I didn't have use cases involving heavy function type processing recently I didn't push much in that direction. You can find some of the code here: https://gist.github.com/PetarKirov/a808c94857de84858accfb094c19bf77#file-rxd-meta2-d-L65-L123
Aug 25 2020