Re: How can overloads be distinguished on attributes alone?
On Monday, 31 July 2023 at 18:15:25 UTC, Jonathan M Davis wrote: On Monday, July 31, 2023 4:55:44 AM MDT Quirin Schroll via Digitalmars-d-learn wrote: Apparently, functions can be overloaded solely distinguished by attributes: ```d void f(ref int x) pure { x = 1; } void f(ref int x) { x = 2; static int s; ++s; } ``` I thought that, maybe, a `pure` context calls the `pure` function and an impure context calls the impure function, but no: Calling `f` leads to an ambiguity error in both contexts. Even if that worked, what about inferred contexts, i.e. templates? In simple cases, they could forward the contexts in which they are called, but you can instantiate a template without calling it. What am I missing here? As things stand, the context in which a function is called is irrelevant. All that matters is the arguments. And actually, allowing it would complicate any functions that infer attributes, potentially in a way that wouldn't work. For instance, if you have a templated function that's trying to infer purity, which one should it call? If it calls the pure one, it could be pure, but if it doesn't, it can't be. Either way, because the context isn't yet pure or not, the context can't be used to determine which should be called. Potentially, the compiler could just choose the pure function in that case, but the problem gets worse as you add more attributes. I reasoned like this up about this point. For instance, what happens when you have a function that's pure but not @safe and one that's @safe but not pure? ```d void f() pure {...} void f() @safe {...} ``` Should the compiler favor calling the pure one or the @safe one? And what if you then add something to the function that isn't @safe? If it was calling the @safe version before, should it switch to the pure one? And if the functions were @safe pure and @system and not pure instead ```d void f() @safe pure {...} void f() @system {...} ``` then changing the @safety or purity of some of the other code in the templated function could result in the loss of both attributes. And the more attributes are involved, the more complex the situation gets. I didn’t even consider multiple attributes “in competition”. At this point, it’s obvious that this can’t work. In effect, we'd be making the attribute inference process have to go in two directions instead of just going from the bottom up, with the added complication that it would potentially need to choose between sets of attributes when choosing which function overload to call. I tried assigning the address to a function pointer to disambiguate which overload I want. Didn’t work. It's not necessarily the case that we couldn't sort all of this out and come up with a clean set of rules that allowed functions that infer their attributes to call the correct function, but it does get pretty complicated, and it comes with the serious downside that there's no guarantee that the overloads even do something similar to one another. Actually, I do think it’s impossible to do the right thing. The spec can only make guesses on what a programmer might want. And when you consider that it's pretty easy for a change in one part of the code to change which attributes are inferred in another part of the code, you could easily end up having a change in one part of your program resulting in drastically different behavior in a seemingly unrelated part of your program. And even worse, that change could be because of a library update, making it that much less obvious which parts of your program could suddenly change behavior due to a change in attributes. Before looking into this, I thought that maybe this was in fact intended. And I'm probably forgetting other issues that this would add to the mix. So, while it may very well be possible to do something along the lines of what you're looking for, I strongly suspect that it's simply not worth it. You might have gotten me wrong. I don’t want to do something with it, I wondered if overloading based on attributes is a thing one has to consider when writing templates or something like that. A simple test was: Can I define those? If so, what happens on a function call? The spec doesn’t say anything about it. As you say, overloads should essentially do the same. Overloads differing in attributes would differ in implementation details such that one can make guarantees and the other might give you better performance or other guarantees. Maybe that’s enough such that, if both implementations have value, they should differ in name (or a kind of tag parameter for overload selection). Filed as https://issues.dlang.org/show_bug.cgi?id=24063
Re: How can overloads be distinguished on attributes alone?
On Monday, July 31, 2023 4:55:44 AM MDT Quirin Schroll via Digitalmars-d-learn wrote: > Apparently, functions can be overloaded solely distinguished by > attributes: > ```d > void f(ref int x) pure { x = 1; } > void f(ref int x) { x = 2; static int s; ++s; } > ``` > > I thought that, maybe, a `pure` context calls the `pure` function > and an impure context calls the impure function, but no: Calling > `f` leads to an ambiguity error in both contexts. Even if that > worked, what about inferred contexts, i.e. templates? In simple > cases, they could forward the contexts in which they are called, > but you can instantiate a template without calling it. > > What am I missing here? As things stand, the context in which a function is called is irrelevant. All that matters is the arguments. And actually, allowing it would complicate any functions that infer attributes, potentially in a way that wouldn't work. For instance, if you have a templated function that's trying to infer purity, which one should it call? If it calls the pure one, it could be pure, but if it doesn't, it can't be. Either way, because the context isn't yet pure or not, the context can't be used to determine which should be called. Potentially, the compiler could just choose the pure function in that case, but the problem gets worse as you add more attributes. For instance, what happens when you have a function that's pure but not @safe and one that's @safe but not pure? void f() pure {...} void f() @safe {...} Should the compiler favor calling the pure one or the @safe one? And what if you then add something to the function that isn't @safe? If it was calling the @safe version before, should it switch to the pure one? And if the functions were @safe pure and @system and not pure instead void f() @safe pure {...} void f() @system {...} then changing the @safety or purity of some of the other code in the templated function could result in the loss of both attributes. And the more attributes are involved, the more complex the situation gets. In effect, we'd be making the attribute inference process have to go in two directions instead of just going from the bottom up, with the added complication that it would potentially need to choose between sets of attributes when choosing which function overload to call. It's not necessarily the case that we couldn't sort all of this out and come up with a clean set of rules that allowed functions that infer their attributes to call the correct function, but it does get pretty complicated, and it comes with the serious downside that there's no guarantee that the overloads even do something similar to one another. And when you consider that it's pretty easy for a change in one part of the code to change which attributes are inferred in another part of the code, you could easily end up having a change in one part of your program resulting in drastically different behavior in a seemingly unrelated part of your program. And even worse, that change could be because of a library update, making it that much less obvious which parts of your program could suddenly change behavior due to a change in attributes. And I'm probably forgetting other issues that this would add to the mix. So, while it may very well be possible to do something along the lines of what you're looking for, I strongly suspect that it's simply not worth it. - Jonathan M Davis
Re: How can overloads be distinguished on attributes alone?
On Monday, 31 July 2023 at 16:52:03 UTC, Dennis wrote: On Monday, 31 July 2023 at 16:09:11 UTC, bachmeier wrote: Is there a reason it would be difficult to make this not compile? No, except that might result in code breakage. The only way you could have code breakage is if you have ``` void f() { } extern(C) void f() { } ``` but your program never calls f. The fix would be to comment out one of the duplicate function definitions.
Re: How can overloads be distinguished on attributes alone?
On Monday, 31 July 2023 at 16:09:11 UTC, bachmeier wrote: Is there a reason it would be difficult to make this not compile? No, except that might result in code breakage.
Re: How can overloads be distinguished on attributes alone?
On Monday, 31 July 2023 at 10:55:44 UTC, Quirin Schroll wrote: What am I missing here? The duplicate definition check doesn't consider whether a function is actually unambiguously callable (without e.g. traits getOverloads), it only prevents creating the same linker symbol multiple time. So you can even do this: ```D void f() { } extern(C) void f() { } ``` But this straight up looks like a bug: ```D void g() { } static void g() { } // static doesn't even do anything here ```
How can overloads be distinguished on attributes alone?
Apparently, functions can be overloaded solely distinguished by attributes: ```d void f(ref int x) pure { x = 1; } void f(ref int x) { x = 2; static int s; ++s; } ``` I thought that, maybe, a `pure` context calls the `pure` function and an impure context calls the impure function, but no: Calling `f` leads to an ambiguity error in both contexts. Even if that worked, what about inferred contexts, i.e. templates? In simple cases, they could forward the contexts in which they are called, but you can instantiate a template without calling it. What am I missing here?
Re: Syntax for Static Import of User Define Attributes
Whenever there might be symbol clash, or when i want to make sure i can identify where something from from i do: ```d import me = my.awesome.module; void main() { me.hi(); } ```
Re: Syntax for Static Import of User Define Attributes
On Friday, 28 July 2023 at 12:20:05 UTC, Steven Schveighoffer wrote: On 7/28/23 8:10 AM, Vijay Nayar wrote: It might be possible to expand the grammar. It seems very specific to UDAs, as it doesn't just throw out `Expression` or whatnot. It probably has to do with the spot that it's in (declaration). Yes, parsing arbitrary expressions after an `@` would result in this: ```D void f(int x) @att in (x > 0) { } ``` Being parsed as: ```D void f(int x) @(att in (x > 0)) { } ``` And things like `@3 + 3` don't look like they would be parsed as `@(3 + 3)`, it looks like `(@3) + 3`. So the syntax as `@(expression)` to make it clear where the expression ends. Then there's `@identifier` and `@identifier(args)` as shorthand for common cases that do look clear. I recently added `@TemplateSingleArgument` so you can do `@"abc"` or `@3` as well. Perhaps the syntax can be expanded to allow `@a.b.c(d)` as well, as well as `@a.b.c!d`, though there's a risk of the rules getting convoluted.
Re: Syntax for Static Import of User Define Attributes
On 7/28/23 8:10 AM, Vijay Nayar wrote: However, this makes me wonder. Is there any reason why the `@` shouldn't recognize the dots in a fully-qualified-name on its own, without the need for parentheses? It might be possible to expand the grammar. It seems very specific to UDAs, as it doesn't just throw out `Expression` or whatnot. It probably has to do with the spot that it's in (declaration). I'll defer to the compiler experts to decide what makes the most sense. -Steve
Re: Syntax for Static Import of User Define Attributes
On Friday, 28 July 2023 at 11:54:12 UTC, Steven Schveighoffer wrote: On 7/28/23 4:15 AM, Vijay Nayar wrote: I tried it and it worked for me. The template-argument syntax is normal. It's just a list of types or expressions (i.e. not a function argument list) What is the error? -Steve You're right, I must have tried something slightly different without realizing it. The syntax that works seems to be to enclose the entire fully-qualified-name of the user-defined-attribute along with all its arguments within parentheses. However, this makes me wonder. Is there any reason why the `@` shouldn't recognize the dots in a fully-qualified-name on its own, without the need for parentheses?
Re: Syntax for Static Import of User Define Attributes
On 7/28/23 4:15 AM, Vijay Nayar wrote: On Thursday, 27 July 2023 at 21:24:44 UTC, Dennis wrote: On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` Try: ```D @(vibe.data.serialization.name("name")) ``` This one causes a different error, because it invokes the template-argument syntax: https://dlang.org/spec/attribute.html#uda I tried it and it worked for me. The template-argument syntax is normal. It's just a list of types or expressions (i.e. not a function argument list) What is the error? -Steve
Re: Syntax for Static Import of User Define Attributes
On Thursday, 27 July 2023 at 21:24:44 UTC, Dennis wrote: On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` Try: ```D @(vibe.data.serialization.name("name")) ``` This one causes a different error, because it invokes the template-argument syntax: https://dlang.org/spec/attribute.html#uda
Re: Syntax for Static Import of User Define Attributes
On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` Try: ```D @(vibe.data.serialization.name("name")) ```
Re: Syntax for Static Import of User Define Attributes
On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` You almost had it. The correct syntax is to enclose the entire attribute (not just the name) in parentheses: ``` class ChatCompletionFunctions { @(vibe.data.serialization.name("name")) string name; } ```
Re: Inferred attributes errors in template function.
On Friday, 27 May 2022 at 09:41:32 UTC, user1234 wrote: [...] on a side note that's funny how dmd manages to systematically print the less interesting message in both case. They are actually correct, I dont know why at some point I thought there was a problem. For the float one it's oviously not pure and for the int one it's not safe... OP wants better error message.
Re: Inferred attributes errors in template function.
On Friday, 27 May 2022 at 08:39:08 UTC, vit wrote: Is in dmd some flag that print errors similarly to this?: ```d void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` //Error: potentially `pure` function `onlineapp.foo!float.foo` cannot call impure function `onlineapp.bar!float.bar` //Error: potentially `pure` function `onlineapp.bar!float.bar` cannot access mutable static data `i` ``` No, there is nothing like this, at least not yet. It's being worked on, though. https://github.com/dlang/dmd/pull/13957 https://github.com/dlang/dmd/pull/12383
Re: Inferred attributes errors in template function.
On Friday, 27 May 2022 at 08:39:08 UTC, vit wrote: Hello, I have this problem: ```d static int i; void bar(T)(){ static if(is(T == int)) (()@system => 1)(); static if(is(T == float)) i = 42; } void foo(T)(){ bar!T(); } void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` } ``` When template function foo is called and its inferred attributes are not compatible with attributes of main, errors are not really useful. Compiler print that foo!float is not pure or foo!int is not @safe but doesn't tell why. Is in dmd some flag that print errors similarly to this?: ```d void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` //Error: potentially `pure` function `onlineapp.foo!float.foo` cannot call impure function `onlineapp.bar!float.bar` //Error: potentially `pure` function `onlineapp.bar!float.bar` cannot access mutable static data `i` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` //Error: potentially `@safe` function `onlineapp.foo!int.foo` cannot call `@system` function `onlineapp.bar!int.bar` //Error: potentially `@safe` function `onlineapp.bar!int.bar` cannot call `@system` delegate `onlineapp.bar!int.bar.__lambda1` } ``` Use `-verrors=context` for dmd ```d static int i; void bar(T)(){ static if(is(T == int)) (()@system => 1)(); static if(is(T == float)) i = 42; } void foo(T)(){ bar!T(); } void main()@safe pure{ foo!long(); foo!float(); /+ onlineapp.d(16): Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` foo!float(); ^ +/ foo!int(); /+onlineapp.d(18): Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` foo!int(); ^ +/ } ```
Re: Inferred attributes errors in template function.
On Friday, 27 May 2022 at 08:39:08 UTC, vit wrote: Hello, I have this problem: ```d static int i; void bar(T)(){ static if(is(T == int)) (()@system => 1)(); static if(is(T == float)) i = 42; } void foo(T)(){ bar!T(); } void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` } ``` [...] on a side note that's funny how dmd manages to systematically print the less interesting message in both case.
Inferred attributes errors in template function.
Hello, I have this problem: ```d static int i; void bar(T)(){ static if(is(T == int)) (()@system => 1)(); static if(is(T == float)) i = 42; } void foo(T)(){ bar!T(); } void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` } ``` When template function foo is called and its inferred attributes are not compatible with attributes of main, errors are not really useful. Compiler print that foo!float is not pure or foo!int is not @safe but doesn't tell why. Is in dmd some flag that print errors similarly to this?: ```d void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` //Error: potentially `pure` function `onlineapp.foo!float.foo` cannot call impure function `onlineapp.bar!float.bar` //Error: potentially `pure` function `onlineapp.bar!float.bar` cannot access mutable static data `i` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` //Error: potentially `@safe` function `onlineapp.foo!int.foo` cannot call `@system` function `onlineapp.bar!int.bar` //Error: potentially `@safe` function `onlineapp.bar!int.bar` cannot call `@system` delegate `onlineapp.bar!int.bar.__lambda1` } ```
Re: How are delegate attributes in fn signature inferred?
On Monday, 23 May 2022 at 13:53:02 UTC, Adam D Ruppe wrote: On Monday, 23 May 2022 at 13:44:53 UTC, wjoe wrote: [...] You can actually make this work with `construct!(int[])` rather than plain `construct`. This is a (really annoying) deficiency in dmd's implementation. (that sdc solved btw proving it can be done just dmd never bothered) [...] I see. I figured the issue was an attribute mismatch. Thanks for the explanation. Very much appreciated!
Re: How are delegate attributes in fn signature inferred?
On Monday, 23 May 2022 at 13:44:53 UTC, wjoe wrote: i.construct((ulong i) {return cast(int)(i+i);}).print; You can actually make this work with `construct!(int[])` rather than plain `construct`. This is a (really annoying) deficiency in dmd's implementation. (that sdc solved btw proving it can be done just dmd never bothered) Where's **pure nothrow @nogc @safe** coming from? That's because it is a delegate literal, so it automatically figured out the tightest thing that works (this is also why it came as `function` instead of `delegate`, since it doesn't use any local variables from the enclosing function, it doesn't need the delegate pointer either). But all those implicitly convert away so it doesn't really matter. The type system allows this, just the crappy implementation can't handle inferring that R when it is mentioned both as R r *and* ElementType!R - the stupid compiler sees ElementType!R and bails out. Thus why you have to help it by telling the type when instantiating it i.construct!(int[])((ulong i) {return cast(int)(i+i);}).print;
How are delegate attributes in fn signature inferred?
Hello, Consider this example: ```d module foo; import std.stdio; import std.algorithm; import std.traits; import std.range; void print(R)(R r) { static assert(isIterable!R); r.each!writeln; } auto construct(R)(R r, ElementType!R delegate(ulong i) fn) { static assert(isIterable!R && hasAssignableElements!R); ulong i = 1; r.each!((ref e) => e = fn(i)); return r; } unittest { int[] i; i.length = 4; i.construct((ulong i) {return cast(int)(i+i);}).print; } ``` ```shell dmd -unittest -main foo.d Error: template 'foo.construct' cannot deduce function from argument types '!()(int[], int function(ulong i) pure nothrow @nogc @safe)', candidates are: 'construct(R)(R r, ElementType!R delegate(ulong i) fn)' ``` Where's **pure nothrow @nogc @safe** coming from? Also, why is *(ulong i) {return cast(int)(i+i);}* passed as a function? The error message for passing a delegate is the same except with *function* substituted for *delegate*.
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 12:16:50 UTC, rumbu wrote: I try to base my reasoning on specification, dmd is not always a good source of information, the lexer is polluted by old features or right now by the ImportC feature, trying to lex D an C in the same time. Alright. I haven't looked at it after the ```importC``` feature was started on. (The lexer code takes a bit of browsing to get used to, but it isn't all that challenging once you are into it.)
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 12:09:55 UTC, Dennis wrote: This should also be fixed in the spec. Filed as: Issue 22543 - [spec] grammar blocks use unspecified notation: https://issues.dlang.org/show_bug.cgi?id=22543 Issue 22544 - [spec] C++ and Objective-C are not single tokens https://issues.dlang.org/show_bug.cgi?id=22544
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 11:25:49 UTC, Ola Fosheim Grøstad wrote: On Thursday, 25 November 2021 at 10:41:05 UTC, Rumbu wrote: I am not asking this questions out of thin air, I am trying to write a conforming lexer and this is one of the ambiguities. I think it is easier to just look at the lexer in the dmd source. The D language does not really have a proper spec, it is more like an effort to document the implementation. I try to base my reasoning on specification, dmd is not always a good source of information, the lexer is polluted by old features or right now by the ImportC feature, trying to lex D an C in the same time. DMD skips the new line if the file was not specified, that's why the "filename" is unexpected on a new line: https://github.com/dlang/dmd/blob/d374003a572fe0c64da4aa4dcc55d894c648514b/src/dmd/lexer.d#L2838 libdparse completely ignores the contents after #line skipping everything until EOL, even a EOF/NUL marker which should end the lexing: https://github.com/dlang-community/libdparse/blob/7112880dae3f25553d96dae53a445c16261de7f9/src/dparse/lexer.d#L1100
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 08:06:27 UTC, rumbu wrote: # //this works line I hate `#`.
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 10:41:05 UTC, Rumbu wrote: Well: ``` #line IntegerLiteral Filespec? EndOfLine ``` Having EndOfLine at the end means for me that there are no other EOLs between, otherwise this syntax should pass but it's not (DMD last): ```d #line 12 "source.d" ``` The lexical grammar section starts with: The source text is decoded from its source representation into Unicode Characters. The Characters are further divided into: WhiteSpace, EndOfLine, Comments, SpecialTokenSequences, and Tokens, with the source terminated by an EndOfFile. What it's failing to mention is how in the lexical grammar rules, spaces denote 'immediate concatenation' of the characters/rules before and after it, e.g.: ``` DecimalDigits: DecimalDigit DecimalDigit DecimalDigits ``` `3 1 4` is not a single `IntegerLiteral`, it needs to be `314`. Now in the parsing grammar, it should mention that spaces denote immediate concatenation of *Tokens*, with arbitrary *Comments* and *WhiteSpace* inbetween. So the rule: ``` AtAttribute: @ nogc ``` Means: an @ token, followed by arbitrary comments and whitespace, followed by an identifier token that equals "nogc". That explains your first example. Regarding this lexical rule: ``` #line IntegerLiteral Filespec? EndOfLine ``` This is wrong already from a lexical standpoint, it would suggest a SpecialTokenSequence looks like this: ``` #line10"file" ``` The implementation actually looks for a # token, skips *WhiteSpace* and *Comment*s, looks for an identifier token ("line"), and then it goes into a custom loop that allows separation by *WhiteSpace* but not *Comment*, and also the first '\n' will be assumed to be the final *EndOfLine*, which is why this fails: ``` #line 12 "source.d" ``` It thinks it's done after "12". In conclusion the specification should: - define the notation used in lexical / parsing grammar blocks - clearly distinguish lexical / parsing blocks - fix up the `SpecialTokenSequence` definition (and maybe change dmd as well) By the way, the parsing grammar defines: ``` LinkageType: C C++ D Windows System Objective-C ``` C++ and Objective-C cannot be single tokens currently, so they are actually 2/3, which is why these are allowed: ```D extern(C ++) void f() {} extern(Objective - C) void g() {} ``` This should also be fixed in the spec. I am not asking this questions out of thin air, I am trying to write a conforming lexer and this is one of the ambiguities. That's cool! Are you writing an editor plugin?
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 10:41:05 UTC, Rumbu wrote: I am not asking this questions out of thin air, I am trying to write a conforming lexer and this is one of the ambiguities. I think it is easier to just look at the lexer in the dmd source. The D language does not really have a proper spec, it is more like an effort to document the implementation.
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 10:10:25 UTC, Dennis wrote: On Thursday, 25 November 2021 at 08:06:27 UTC, rumbu wrote: Also, this works also for #line, even if the specification tells us that all tokens must be on the same line Where does it say that? Well: ``` #line IntegerLiteral Filespec? EndOfLine ``` Having EndOfLine at the end means for me that there are no other EOLs between, otherwise this syntax should pass but it's not (DMD last): ```d #line 12 "source.d" ``` I am not asking this questions out of thin air, I am trying to write a conforming lexer and this is one of the ambiguities.
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 08:06:27 UTC, rumbu wrote: Also, this works also for #line, even if the specification tells us that all tokens must be on the same line Where does it say that?
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 08:06:27 UTC, rumbu wrote: Is that ok or it's a lexer bug? @ (12) does exactly what I would expect. @nogc I always assumed was a single token, but the spec says otherwise. I suppose that makes sense. #line is dicier as it is not part of the grammar proper; however the spec describes it as a 'special token sequence', and comments are not tokens, so I think the current behaviour is correct.
Re: Attributes (lexical)
On Thursday, 25 November 2021 at 08:06:27 UTC, rumbu wrote: Is that ok or it's a lexer bug? Yes. The lexer just eats whitespace and the parser accepts way too much.
Attributes (lexical)
Just playing around with attributes. This is valid D code: ```d @ nogc: //yes, this is @nogc in fact, even some lines are between @ /* i can put some comments */ /** even some documentation */ // single line comments also (12) // yes, comments and newlines are allowed between attribute and declaration int x; //@(12) is attached to declaration ``` Is that ok or it's a lexer bug? Also, this works also for #line, even if the specification tells us that all tokens must be on the same line ```d # //this works line /* this too */ 12 //this is #line 12 ```
Re: How do I assign attributes of a function to another function?
On Friday, 5 November 2021 at 06:19:16 UTC, Li30U wrote: ...e.g. ```d // ... mixin ("ReturnType /*...snip...*/ " ~ member ~ "()(Parameters! /*...snip...*/ ``` Note the `()` before parameter list. This would make your member function a function template, for which attributes will be inferred by the compiler based on the calls you make in the function body. Of course, making it a template like this makes it non-composable with that same type as you're only inspecting functions, so you wouldn't be able to do e.g. a Group!(Group!(A, 3), 4);
Re: How do I assign attributes of a function to another function?
On Friday, 5 November 2021 at 06:19:16 UTC, Li30U wrote: I am creating a templated object that is a storehouse for a heap object and executes their methods and returns an array of results. With the help of a template, I want to achieve this, but I want to assign the same attributes to the function. How can one pass the attributes of a function to another function? There's https://dlang.org/spec/traits.html#getFunctionAttributes . Or you could define your functions as function templates, letting the compiler infer attributes. Especially as it looks like you function's attributes may not be made the same as the ones you defer to: since you're allocating with the GC, your function cannot be @nogc even if a deferred one can.
How do I assign attributes of a function to another function?
I am creating a templated object that is a storehouse for a heap object and executes their methods and returns an array of results. With the help of a template, I want to achieve this, but I want to assign the same attributes to the function. How can one pass the attributes of a function to another function? ```d template Group(T, int objects) { struct Group { enum __length = __traits(allMembers, T).length; T[objects] __objects; this(T[objects] __objctor) @safe { __objects = __objctor; } static foreach (member; __traits(allMembers, T)) { static if ( __traits(getVisibility, __traits(getMember, T, member)) != "private" && __traits(getVisibility, __traits(getMember, T, member)) != "protected") { static if (isFunction!(__traits(getMember, T, member))) { mixin ("ReturnType!(__traits(getMember, T, member))[] " ~ member ~ "(Parameters!(__traits(getMember, T, member)) args) { ReturnType!(__traits(getMember, T, member))[] results; foreach (e; __objects) results ~= e." ~ member ~ "(args); return results; }"); }else static if (member != "Monitor") { mixin ("typeof(__traits(getMember, T, member))[] " ~ member ~ "() { typeof(__traits(getMember, T, member))[] results; foreach (e; __objects) results ~= e." ~ member ~ "; return results; }"); } } } } } ```
Re: interface function member declarations needing parameter attributes ?
On Sunday, 18 July 2021 at 11:03:24 UTC, Adam D Ruppe wrote: Fun fact there: any child implementations do NOT need to specify the attribute there; the compiler will copy it from the interface for you. I suppose these are the day-to-day minor details you can rely on to avoid typing a lot of things, but, in the end, I prefer to state things clearly because in the event someone need to port my code I'll be making his life miserable trying to understand all these defaults; and I am not talking explicitly D here, I am talking any language, I did never forget a project in which I was involved porting a big development from C++ ... it took almost 3X the time we all think back then it needed to. From that time on I try to avoid fancy things with code whenever possible -just common sense.
Re: interface function member declarations needing parameter attributes ?
On Sunday, 18 July 2021 at 03:27:04 UTC, someone wrote: I have an interface with function members *not* being declared @safe (at first glance it seemed irrelevant to me just to mark @safe a declaration and not an actual implementation). Yeah, that'd be promising all child implementations are @safe. Fun fact there: any child implementations do NOT need to specify the attribute there; the compiler will copy it from the interface for you. interface I { @safe void foo(); } class C : I { void foo(); // automatically copies @safe from interface } If you leave it off, you are not promising safe, but children are still allowed to use it anyway. The general rule is child classes can be stricter than the parent if they want to be, but they don't have to be. interface I { void foo(); // not safe } class C : I { void foo(); // OK, not safe, interface didn't force it } class C2 : I { @safe void foo(); // OK, class can be stricter than parent. now safe if used through C2, but the interface can't promise it is C2 instead of C, so it still follows @system rules. } class C3 : C2 { override void foo(); // automatically @safe since it picks it up from parent C2 }
Re: interface function member declarations needing parameter attributes ?
On Saturday, 17 July 2021 at 21:01:00 UTC, Adam Ruppe wrote: From the interface perspective: are these signatures identical or not ? No, they are very different. This helped me solve an issue that I carried since a few days ago: I have an interface with function members *not* being declared @safe (at first glance it seemed irrelevant to me just to mark @safe a declaration and not an actual implementation). I also have former @safe member functions in classes implementing this interface that at some point I did have to take out the @safe declarations because the compiler didn't like them anymore due to some change I made which I didn't link to them, and from the on I did not quite understand why it was complaining since everything seemed perfect to me (as usual ha). Now that I marked the ones in the interface @safe I can also mark the ones implementing them @safe again and now everything is @safe and working properly. Another day, another lesson learned.
Re: interface function member declarations needing parameter attributes ?
On Saturday, 17 July 2021 at 22:48:00 UTC, Adam D Ruppe wrote: On Saturday, 17 July 2021 at 22:43:15 UTC, someone wrote: So the lesson learned is that interfaces can also mandate member function's parameter attributes then ... right ? A subclass must accept anything the parent class can, but it can also make it stricter if you want. class Base { void foo(Object o) {} } class Derived : Base { override void foo(const Object o) {} } That's legal because const also accepts mutable. Derived is stricter than Base which is permitted. But the other way around: class Base { void foo(const Object o) {} } class Derived : Base { override void foo(Object o) {} } is NOT allowed because the mutable thing in derived cannot be passed back to the base interface implicitly. Perfectly clear; thanks Adam :) !
Re: interface function member declarations needing parameter attributes ?
On Saturday, 17 July 2021 at 22:43:15 UTC, someone wrote: So the lesson learned is that interfaces can also mandate member function's parameter attributes then ... right ? A subclass must accept anything the parent class can, but it can also make it stricter if you want. class Base { void foo(Object o) {} } class Derived : Base { override void foo(const Object o) {} } That's legal because const also accepts mutable. Derived is stricter than Base which is permitted. But the other way around: class Base { void foo(const Object o) {} } class Derived : Base { override void foo(Object o) {} } is NOT allowed because the mutable thing in derived cannot be passed back to the base interface implicitly.
Re: interface function member declarations needing parameter attributes ?
On Saturday, 17 July 2021 at 21:01:00 UTC, Adam Ruppe wrote: No, they are very different. So the lesson learned is that interfaces can also mandate member function's parameter attributes then ... right ? But you also don't gain much from const here and that ref is probably actively harmful so i wouldn't use them here. ref is gone.
Re: interface function member declarations needing parameter attributes ?
On Saturday, 17 July 2021 at 20:42:06 UTC, someone wrote: From the interface perspective: are these signatures identical or not ? No, they are very different. But you also don't gain much from const here and that ref is probably actively harmful so i wouldn't use them here.
interface function member declarations needing parameter attributes ?
```d public interface intefaceWhatever { public bool doSomething( dstring lstrID, classX robjX ); } ``` vs ```d public interface intefaceWhatever { public bool doSomething( const dstring lstrID, ref classX robjX ); } ``` From the interface perspective: are these signatures identical or not ? Is the latter needed ... or if not, makes sense as best practice ?
Re: Is it possible to set function attributes conditionally?
On Friday, 4 June 2021 at 11:36:09 UTC, Adam D. Ruppe wrote: On Friday, 4 June 2021 at 11:33:32 UTC, wjoe wrote: This is a contrived example. In reality I would use this with custom array, hash map and other container implementations so I could use them in @nogc territory by just switching out the allocator. If they are templates, just don't specify attributes and the compiler will infer them for you. If they are not templates, you have to do a separate copy under version or static if. That's good to know. Thanks :) A separate copy is exactly what I wanted to avoid but since they are templates it's np.
Re: Is it possible to set function attributes conditionally?
On Friday, 4 June 2021 at 11:33:32 UTC, wjoe wrote: This is a contrived example. In reality I would use this with custom array, hash map and other container implementations so I could use them in @nogc territory by just switching out the allocator. If they are templates, just don't specify attributes and the compiler will infer them for you. If they are not templates, you have to do a separate copy under version or static if.
Is it possible to set function attributes conditionally?
Hi, Consider Allocators, e.g.: ```d struct Mallocator { enum usesGC = false; /// implement alloc, free, etc. @nogc } struct GCAllocator { enum usesGC = true; /// implement alloc, free, etc. via the GC } ``` Now I want to have the function attributes set depending on the allocator implementation ```d template AutoGC(ALLOCATOR) if (isAllocator!ALLOCATOR) { static if (!ALLOCATOR.usesGC) AutoGC = pragma(attrib, @nogc); else AutoGC = pragma(attrib, none); } @AutoGC!ALLOCATOR void fun(ALLOCATOR)() if(isAllocator!ALLOCATOR) { void* p = ALLOCATOR.alloc(1024); // do something with p ALLOCATOR.free(p); } ``` So fun!Mallocator would be @nogc and fun!GCAllocator wouldn't be @nogc. This is a contrived example. In reality I would use this with custom array, hash map and other container implementations so I could use them in @nogc territory by just switching out the allocator. Is it possible to do something like this ?
Re: opApply and attributes
On Tuesday, 14 July 2020 at 00:17:14 UTC, solidstate1991 wrote: Something like that, but with @safe, pure, etc. attributes. I've tried to "bruteforce" it by generating functions with combinations of attributes, and it kinda works, but is a very janky solution. I'll brainstorm some DIP to fix this issue.
Re: opApply and attributes
On Tuesday, 7 July 2020 at 20:53:05 UTC, Ali Çehreli wrote: I am not sure whether I understand it correctly but there has been a request for opApply() to gain the attributes of the delegate (or the range?). In other words, "transfer the attributes to opApply". This is needed because I want opApply() to work with any foreach body, attributes of which opApply() cannot know. I am sure I created an issue on Dlang bug tracker for Weka on this topic but I can't find it now. (Aside: The search boxes on the bug tracker are inferior to the automatic search feature that works when creating a bug.) Anyway, this one seems related: https://issues.dlang.org/show_bug.cgi?id=7543 Ali Something like that, but with @safe, pure, etc. attributes.
Re: opApply and attributes
On 7/6/20 5:20 PM, solidstate1991 wrote:> See implementation of data structure here: > https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L565 > > > If I try to compile this code, it'll fail, limiting it's usecase: > > @safe pure unittest { > alias IntMap = TreeMap!(int, int, false); > IntMap test; > test[5] = 5; > test[7] = 7; > test[3] = 3; > foreach(elem, key; test) { > assert(elem == key); > } > } I am not sure whether I understand it correctly but there has been a request for opApply() to gain the attributes of the delegate (or the range?). In other words, "transfer the attributes to opApply". This is needed because I want opApply() to work with any foreach body, attributes of which opApply() cannot know. I am sure I created an issue on Dlang bug tracker for Weka on this topic but I can't find it now. (Aside: The search boxes on the bug tracker are inferior to the automatic search feature that works when creating a bug.) Anyway, this one seems related: https://issues.dlang.org/show_bug.cgi?id=7543 Ali
Re: opApply and attributes
On Tuesday, 7 July 2020 at 13:33:41 UTC, Paul Backus wrote: You can make opApply a template: int opApply(Dg)(Dg dg) if (is(Dg : scope int delegate(ref E))) { // etc. } Because `scope int delegate(ref E) @safe` implicitly converts to `scope int delegate(ref E)`, this version will accept both @safe and non-@safe delegates. (And likewise for the other function attributes.) Unfortunately this doesn't really work, even with explicitly defined foreach arguments.
Re: opApply and attributes
On Tuesday, 7 July 2020 at 13:33:41 UTC, Paul Backus wrote: You can make opApply a template: int opApply(Dg)(Dg dg) if (is(Dg : scope int delegate(ref E))) { // etc. } Because `scope int delegate(ref E) @safe` implicitly converts to `scope int delegate(ref E)`, this version will accept both @safe and non-@safe delegates. (And likewise for the other function attributes.) Yeah, but unfortunately then this won't work: foreach(elem; test) { assert(elem == key); } you'd have to spell out the types for `elem`.
Re: opApply and attributes
On Tuesday, 7 July 2020 at 00:20:40 UTC, solidstate1991 wrote: See implementation of data structure here: https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L565 If I try to compile this code, it'll fail, limiting it's usecase: @safe pure unittest { alias IntMap = TreeMap!(int, int, false); IntMap test; test[5] = 5; test[7] = 7; test[3] = 3; foreach(elem, key; test) { assert(elem == key); } } You can make opApply a template: int opApply(Dg)(Dg dg) if (is(Dg : scope int delegate(ref E))) { // etc. } Because `scope int delegate(ref E) @safe` implicitly converts to `scope int delegate(ref E)`, this version will accept both @safe and non-@safe delegates. (And likewise for the other function attributes.)
opApply and attributes
See implementation of data structure here: https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L565 If I try to compile this code, it'll fail, limiting it's usecase: @safe pure unittest { alias IntMap = TreeMap!(int, int, false); IntMap test; test[5] = 5; test[7] = 7; test[3] = 3; foreach(elem, key; test) { assert(elem == key); } } I know that implementing foreach with other means do exist, and I used them in my other data structures, but it's much more difficult (and potentially slower) to implement that within a binary search tree. Should I change the `opApply` into the `popfront` - `front` - `empty` trinity, or write a template that overrides all the potential attribute combinations? Maybe D needs a template for attributes somehow, or something like that.
Re: Get unknown symbol (struct, method, class) tagged with User Defined Attributes
On 2020-05-12 06:02, Steven Schveighoffer wrote: If you want a list of ALL symbols that have the UDA in the application, that would require some form of runtime reflection (like Java). D has very limited support for runtime reflection. In D, you would use some form of registration to tell the system about your symbols. I think it's possible to implement the `RTInfo` template in `object.d`. But that requires a custom druntime. `RTInfo` is a template that is instantiated once for each type in the program. -- /Jacob Carlborg
Re: Get unknown symbol (struct, method, class) tagged with User Defined Attributes
On Tuesday, 12 May 2020 at 04:02:18 UTC, Steven Schveighoffer wrote: In the case of serialization/deserialization, you give an instance of a type to serialize or deserialize. Then the library can search the symbols inside that type to see if any has the UDA you are looking for. In the Rust example, there is a line of code: let p: Person = serde_json::from_str(data)?; I'm assuming that this conversion is detected and figured out (i.e. this is how serde "finds" the type desired). For D, it would look something like: auto p = serde_json.from_str!Person(data); If you want a list of ALL symbols that have the UDA in the application, that would require some form of runtime reflection (like Java). D has very limited support for runtime reflection. In D, you would use some form of registration to tell the system about your symbols. -Steve Thanks for the feedback. I've got a better idea of what is and isn't possible now. I'll see about looking at one or two D JSON libraries to see how they approach things. It should help shed some more light on the subject.
Re: Get unknown symbol (struct, method, class) tagged with User Defined Attributes
On 5/11/20 11:30 PM, Doug wrote: On Tuesday, 12 May 2020 at 02:53:53 UTC, Adam D. Ruppe wrote: see std.traits.getSymbolsByUDA Thanks for the link. I did see that one. But that function searches within known symbols. My use case if for a library that's used outside of my application. In that case, I wouldn't know which symbol a library applies an annotation to. This is why I asked for how to get a list of unknown symbols from a known UDA. To use a REST frame work as an example, I would supply a @GET annotation and a user would apply that annotation to a handler method. I wouldn't know the method or module in advanced so I wouldn't know which symbol to pass to "getSymbolsByUDA" of any of it's sibling functions. I'm curious to see what I'd be able to do if this is possible. So the idea is that you know the parent symbol. In the case of serialization/deserialization, you give an instance of a type to serialize or deserialize. Then the library can search the symbols inside that type to see if any has the UDA you are looking for. In the Rust example, there is a line of code: let p: Person = serde_json::from_str(data)?; I'm assuming that this conversion is detected and figured out (i.e. this is how serde "finds" the type desired). For D, it would look something like: auto p = serde_json.from_str!Person(data); If you want a list of ALL symbols that have the UDA in the application, that would require some form of runtime reflection (like Java). D has very limited support for runtime reflection. In D, you would use some form of registration to tell the system about your symbols. -Steve
Re: Get unknown symbol (struct, method, class) tagged with User Defined Attributes
On Tuesday, 12 May 2020 at 02:53:53 UTC, Adam D. Ruppe wrote: see std.traits.getSymbolsByUDA Thanks for the link. I did see that one. But that function searches within known symbols. My use case if for a library that's used outside of my application. In that case, I wouldn't know which symbol a library applies an annotation to. This is why I asked for how to get a list of unknown symbols from a known UDA. To use a REST frame work as an example, I would supply a @GET annotation and a user would apply that annotation to a handler method. I wouldn't know the method or module in advanced so I wouldn't know which symbol to pass to "getSymbolsByUDA" of any of it's sibling functions. I'm curious to see what I'd be able to do if this is possible.
Re: Get unknown symbol (struct, method, class) tagged with User Defined Attributes
On Tuesday, 12 May 2020 at 02:51:39 UTC, Doug wrote: So far I've only seen a way to get unknown UDAs from known symbols but not how to get unknown symbols from UDAs. Is there any documentation for how to get a list of symbols annotated with a specific UDA? see std.traits.getSymbolsByUDA http://dpldocs.info/experimental-docs/std.traits.getSymbolsByUDA.html there's some caveats, like it only searches one particular parent symbol for its children (that's because the way this works is you reflect through children checking each symbol child's uda list to see if it is present) but it basically works for many things at least contained per-module. you can pass each module you care about in though to generate a more full list
Get unknown symbol (struct, method, class) tagged with User Defined Attributes
I've seen a lot of examples of how to get a list of User Defined Attributes from a known symbol but I haven't seen any for how to get a list of symbols when only the UDA is known. The use case is the same as seen in Rust with Serde[1]. Library users annotate a struct to mark it for serialization. In Java and Spring, you can mark a method with @Secured to add authorization to an endpoint[2]. In both of these cases, you have no idea which symbol the UDA will be applied to. So far I've only seen a way to get unknown UDAs from known symbols but not how to get unknown symbols from UDAs. Is there any documentation for how to get a list of symbols annotated with a specific UDA? 1: Serde: https://github.com/serde-rs/json 2: Spring: https://www.baeldung.com/spring-security-method-security
Re: Extracting user defined attributes on function parameters
On Saturday, 18 April 2020 at 09:19:48 UTC, Simen Kjærås wrote: On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh wrote: I wonder if the ultimate cause of the above case is ultimately caused by the change to import semantics that hid private symbols from outside the module. Perhaps something, somewhere, is triggering an illegal access of a private symbol, which percolates up the call/instantiation stack and causing what appears to be a strange compiler discrepancy. Not unlikely. Importing the module defining S in the module defining ParameterDefaults does indeed make things compile. Hiding S by making it private makes the error return. It's not about private. Or even if it is, there's other issues. Proof: struct A { struct S {} void f(@S int = 3); pragma(msg, Issue20744!f); } template Issue20744(func...) { static if (is(typeof(func[0]) PT == __parameters)) { alias Issue20744 = (PT args) {}; } } -- Simen
Re: Extracting user defined attributes on function parameters
On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh wrote: I wonder if the ultimate cause of the above case is ultimately caused by the change to import semantics that hid private symbols from outside the module. Perhaps something, somewhere, is triggering an illegal access of a private symbol, which percolates up the call/instantiation stack and causing what appears to be a strange compiler discrepancy. Not unlikely. Importing the module defining S in the module defining ParameterDefaults does indeed make things compile. Hiding S by making it private makes the error return. (for whatever reason your message isn't visible in the web interface) -- Simen
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 18:05:39 UTC, Jean-Louis Leroy wrote: Interesting example, but all hope is not lost. `a` could (should?) be passed as an alias in __parameters. Well, __parameters itself actually kinda works. The compiler knows it is an expression and can stringify it or evaluate it on demand for you... but how to express that in D code is pretty weird and idk how to library that. Using in-site for various things can be done but putting it in a lib is idk.
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 18:05:39 UTC, Jean-Louis Leroy wrote: Interesting example, but all hope is not lost. `a` could (should?) be passed as an alias in __parameters. Okay I take this back...
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 17:48:06 UTC, Adam D. Ruppe wrote: On Friday, 17 April 2020 at 17:31:32 UTC, Jean-Louis Leroy wrote: Well, can't do. I need this purely at compile time, and cross-module. And the CTFE engine gets weird with it too dmd will have to fix this. But default parameters might not be possible in general at CT anyway... it is actually possible to define it to a variable. Observe: int a; void f(int arg = a) { // default arg is to use the global... import std.stdio; writeln(arg); } void main() { f(); // 0 this time a = 4; // and it can be changed at runtime! f(); // will now say 4 } Interesting example, but all hope is not lost. `a` could (should?) be passed as an alias in __parameters.
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 17:31:32 UTC, Jean-Louis Leroy wrote: Well, can't do. I need this purely at compile time, and cross-module. And the CTFE engine gets weird with it too dmd will have to fix this. But default parameters might not be possible in general at CT anyway... it is actually possible to define it to a variable. Observe: int a; void f(int arg = a) { // default arg is to use the global... import std.stdio; writeln(arg); } void main() { f(); // 0 this time a = 4; // and it can be changed at runtime! f(); // will now say 4 }
Re: Extracting user defined attributes on function parameters
On Fri, Apr 17, 2020 at 05:33:23PM +, Simen Kjærås via Digitalmars-d-learn wrote: > On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote: [...] > > So pragma(msg) is doing something really weird, the bug doesn't > > appear to be in Phobos per se, I think it is the compiler doing the > > wrong thing, it seems to me it works inside a function scope but not > > at module scope.. > > It's even more fascinating - the issue doesn't occur if > ParameterDefaults is defined in the same module that it's used in, and > it works if there's a type with the same name as the UDA. Reducing the > code as much as I can, I get this: [...] > The above code works, and prints "3". If you move ParameterDefaults to > a different module, something like this: [...] > Then you get an error message about 'undefined identifier S'. Add some > kind of S to bar, and you get an error message about S not being > readable at compile-time or things just work if it is readable. It > seems the UDA is being looked up in the wrong context. This is reminiscient of a bug I found recently, the ultimate cause of which is accessing a private symbol across modules, which is verboten, but it manifested itself in a way that appeared completely unrelated -- it turned an attribute-inferred function into @system where one expected @safe, which percolated up the call stack and ended up as a template mismatch error, which then shunted the template resolution into another overload which finally generated a totally unrelated compile error (very unhelpful!). I wonder if the ultimate cause of the above case is ultimately caused by the change to import semantics that hid private symbols from outside the module. Perhaps something, somewhere, is triggering an illegal access of a private symbol, which percolates up the call/instantiation stack and causing what appears to be a strange compiler discrepancy. Or perhaps it's a compiler bug. :-D T -- It is of the new things that men tire --- of fashions and proposals and improvements and change. It is the old things that startle and intoxicate. It is the old things that are young. -- G.K. Chesterton
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote: void main() { import std.stdio; writeln(ParameterDefaults!f.stringof); } and it is fine. Well, can't do. I need this purely at compile time, and cross-module. That's for supporting UDAs and default parameter values in openmethods. If you want a peek at what I am up to, see here: https://github.com/jll63/openmethods.d/blob/bolts-reflection/source/bolts/reflection/metafunction.d
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote: This part seems fine... pragma(msg, ParameterDefaults!f.stringof); It is this, specifically, that causes the problem. Replace it with: void main() { import std.stdio; writeln(ParameterDefaults!f.stringof); } and it is fine. So pragma(msg) is doing something really weird, the bug doesn't appear to be in Phobos per se, I think it is the compiler doing the wrong thing, it seems to me it works inside a function scope but not at module scope.. It's even more fascinating - the issue doesn't occur if ParameterDefaults is defined in the same module that it's used in, and it works if there's a type with the same name as the UDA. Reducing the code as much as I can, I get this: struct S {} void f(@S int = 3); pragma(msg, ParameterDefaults!f.stringof); template ParameterDefaults(func...) { import std.traits : FunctionTypeOf; static if (is(FunctionTypeOf!(func[0]) PT == __parameters)) { enum ParameterDefaults = (PT[0..1] args) @trusted { return *&(args[0]); }(); } } The above code works, and prints "3". If you move ParameterDefaults to a different module, something like this: - import bar; struct S {} void f(@S int = 3); pragma(msg, ParameterDefaults!f.stringof); - module bar; template ParameterDefaults(func...) { static if (is(typeof(func[0]) PT == __parameters)) { enum ParameterDefaults = (PT[0..1] args) @trusted { return *&(args[0]); }(); } } - Then you get an error message about 'undefined identifier S'. Add some kind of S to bar, and you get an error message about S not being readable at compile-time or things just work if it is readable. It seems the UDA is being looked up in the wrong context. -- Simen
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 16:40:15 UTC, Jean-Louis Leroy wrote: Alas the presence of parameter UDAs breaks std.traits.ParameterDefaults: import std.traits; struct attr; void f(@attr int); This part seems fine... pragma(msg, ParameterDefaults!f.stringof); It is this, specifically, that causes the problem. Replace it with: void main() { import std.stdio; writeln(ParameterDefaults!f.stringof); } and it is fine. So pragma(msg) is doing something really weird, the bug doesn't appear to be in Phobos per se, I think it is the compiler doing the wrong thing, it seems to me it works inside a function scope but not at module scope.. I'd like to understand why taking a slice of __parameters vs fetching the first element matters. What is the (meta?) type of __parameters[0..1]? The first element alone becomes a type. The slice maintains the magic data inside the compiler; it contains stuff the rest of the language cannot express by itself except in parameter lists. It is weird. collapses into a string. Makes me think of wave functions in quantum mechanics ;-) well it is dependent on when the compiler observes it so lol
Re: Extracting user defined attributes on function parameters
Alas the presence of parameter UDAs breaks std.traits.ParameterDefaults: import std.traits; struct attr; void f(@attr int); pragma(msg, ParameterDefaults!f.stringof); Error: dmd -c bug.d bug.d(4): Error: undefined identifier `attr`, did you mean variable `ptr`? /home/jll/dlang/dmd-2.090.1/linux/bin64/../../src/phobos/std/traits.d(1526): Error: template instance `std.traits.ParameterDefaults!(f).Get!0LU` error instantiating /home/jll/dlang/dmd-2.090.1/linux/bin64/../../src/phobos/std/traits.d(1529): instantiated from here: `Impl!0LU` bug.d(6):instantiated from here: `ParameterDefaults!(f)` bug.d(6):while evaluating `pragma(msg, ParameterDefaults!(f).stringof)` I filed a bug report (20744). And examined the code of ParameterDefaults. I think I understand how it works, for the most part, but I haven't been able to find a fix yet. I'd like to understand why taking a slice of __parameters vs fetching the first element matters. What is the (meta?) type of __parameters[0..1]? I think I'd need to make a copy of it, minus the UDAs tucked at the beginning. But I haven't found a way of splitting it into smaller components. I tried using indexation and variadic template parameters, but it always collapses into a string. Makes me think of wave functions in quantum mechanics ;-)
Re: Extracting user defined attributes on function parameters
Thanks to both of you! As part of implementing full support for attributes in openmethods, I am developing a reflection library. That helped a lot. is() is a bit weird, but I described it in my "D Cookbook" to some success... I am going to order it...even though it is not available on Kindle ;-)
Re: Extracting user defined attributes on function parameters
On Wed, Apr 15, 2020 at 12:01:51AM +, Adam D. Ruppe via Digitalmars-d-learn wrote: [...] > is() is a bit weird, but I described it in my "D Cookbook" to some > success... and writing that description helped me make sense of it. > The docs list like seven forms of it, but they are mostly just one big > thing with a lot of optional pieces you can leave out, coupled with a > little bit of magic when you use certain keywords, like __parameters. is(T params == __parameters) is one of the most evil arcane black magic corners of D, as I wrote here: https://forum.dlang.org/post/mailman.1197.1379014886.1719.digitalmars-d-le...@puremagic.com It feels like it was shoehorned into is() because that was the most convenient place at the time, but it's really a strange arcane beast that has its own quirky behaviours that are different from anything else I've seen in D. T -- The irony is that Bill Gates claims to be making a stable operating system and Linus Torvalds claims to be trying to take over the world. -- Anonymous
Re: Extracting user defined attributes on function parameters
On Tuesday, 14 April 2020 at 21:54:14 UTC, Jean-Louis Leroy wrote: O.kay. It looks like `is` is D's Swiss army chainsaw. Aye, is and __traits are the two built-in compile-time reflection avenues. The phobos std.traits things (for the most part, look at the source for the default parameter values thing and lol you'll see some of them get quite involved) wrap them. is() is a bit weird, but I described it in my "D Cookbook" to some success... and writing that description helped me make sense of it. The docs list like seven forms of it, but they are mostly just one big thing with a lot of optional pieces you can leave out, coupled with a little bit of magic when you use certain keywords, like __parameters. https://dlang.org/spec/expression.html#is_expression I like to think of it as a kind of magic variable declaration is(SomeExistingType yourOptionalIdenfier == some_optional_pattern) (or you can use : instead of == for a looser match. == is equality, and : indicates implicit conversion, like how class Foo : Interface can implicitly convert to Interface, so `is(Foo : Interface)` passes. If you leave off both the ident and the pattern, it just check is the type is a type: static if(is(Object)) // passed because Object is a type static if(is(10)) // fails because 10 isn't a type, it is a value static if(is(adasdsa)) // fails because undefined identifier If you provide the optional identifier, it aliases the match inline for you. I think of the syntax as being like a variable declaration. So just like int a; // defines a new variable with the name "a" static if(is(Object a)) // defines a new alias with the name "a" being the same as Object Then you add on the pattern. These are generally written like the variable declaration too, but you can define placeholders. Simple example: static if(is(typeof(a) == int)) more complex example: static if(is(typeof(a) == T[], T)) In that one, the pattern is "T[]", looking like a type, but then since I specified ", T" afterward, it means T is a placeholder. So that would match if typeof(a) is some kind of array, and then T gets the element type. int[] a; static if(is(typeof(a) == T[], T)) // passes because a is an array, T == int Those can get pretty complex because you're allowed to add as many placeholders as you need for an arbitrarily complex pattern, though I prefer to keep it kinda simple and use two levels of static if to cover more complicated things. Then the last magic is the pattern on the right-hand side can be various keywords. static if(is(Object == class)) passes if Object is a class. You can also do that with struct, interface, union, const, immutable, and shared. But if you look at the docs, you see there are a few other magic keywords too, like `enum`, return, function, delegate, super, and __parameters. They still match what you expect basically - if it is a function pointer, or an enum, etc., but the real magic is they change what the alias you can define in the is() expression refers to. So then it isn't just a convenience alias for the condition, it actually becomes an aspect of that type, like the return type, or the params, or the parent class. So yes a swiss army chainsaw :P but once you know its few tricks and patterns it isn't as hard as the docs make it look.
Re: Extracting user defined attributes on function parameters
On Tuesday, 14 April 2020 at 21:44:51 UTC, Adam D. Ruppe wrote: On Tuesday, 14 April 2020 at 21:35:12 UTC, Jean-Louis Leroy wrote: I can see them: There's some weird tricks to it. Check out my old blog sidebar about it here: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_02_11.html#how-to-get-uda-on-a-function-param O.kay. It looks like `is` is D's Swiss army chainsaw. Yeah I never read the `is` doc properly. Now I am beginning to understand how `std.traits.Parameters` works. Thanks!
Re: Extracting user defined attributes on function parameters
On Tuesday, 14 April 2020 at 21:35:12 UTC, Jean-Louis Leroy wrote: I can see them: There's some weird tricks to it. Check out my old blog sidebar about it here: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_02_11.html#how-to-get-uda-on-a-function-param
Extracting user defined attributes on function parameters
I can see them: import std.traits; struct foo; struct bar; void f(@foo int, @foo @bar @("baz") real); pragma(msg, Parameters!f); // (@(foo) int, @(tuple(tuple(foo), tuple(bar)), tuple("baz")) real) ...but I cannot find how to get hold of them: pragma(msg, (Mystery!f)[0]); // foo pragma(msg, __traits(mystery, f)[0]); // foo And besides the structure looks weird for the second argument. It's as if the UDAs were applied to one another, from left to right. I did search the documentation and google for 1/2 hour.
Re: linker aliases to carry dlang attributes for externs
On Sunday, 12 April 2020 at 23:14:42 UTC, Bruce Carneal wrote: Could dlang compilers emit aliases for extern(C) and extern(C++) routines that would carry dlang specific information? (@safe, @nogc, nothrow, ...) I'm thinking two symbols. The first as per normal C/C++, and the second as per normal dlang with a "use API {C, C++, ...}" suffix. ABI, not API.
linker aliases to carry dlang attributes for externs
Could dlang compilers emit aliases for extern(C) and extern(C++) routines that would carry dlang specific information? (@safe, @nogc, nothrow, ...) I'm thinking two symbols. The first as per normal C/C++, and the second as per normal dlang with a "use API {C, C++, ...}" suffix.
Re: Conditional Attributes
On Thursday, 20 February 2020 at 17:41:54 UTC, Dennis wrote: On Tuesday, 18 February 2020 at 17:11:55 UTC, Marcel wrote: Say I have a struct where every member function can either be static or not depending on a template parameter. Is there a simple way to do this? The best I can think of is: ``` mixin template maybeStatic() { void foo() { // implementation } } struct S(bool condition) { static if (condition) { static { mixin maybeStatic; } } else { mixin maybeStatic; } } ``` What do you need this for? It seems like an unusual situation to me. That will do, thank you! I'm making an allocator library similar to what Andrei Alexandrescu presented at CppCon. Since some allocators may not have state, those that inherit* from them may need to have every member function marked as static. *I'm using mixins instead of inheritance.
Re: Conditional Attributes
On Friday, 21 February 2020 at 01:41:21 UTC, Steven Schveighoffer wrote: On 2/18/20 12:11 PM, Marcel wrote: Hello! Say I have a struct where every member function can either be static or not depending on a template parameter. Is there a simple way to do this? Like, for example: struct Foo(Condition) { static if (Condition) static: void Bar() {} void Baz() {} } Since D conditional compilation must always be a valid declaration or statement, you cannot do something like this. The closest you can do is to use mixins, which means you have to write everything inside strings. It has been proposed quite a few times to have a way to enable/disable attributes based on a compile-time boolean. But it's never come close to getting included. -Steve That's a shame...
Re: Conditional Attributes
On 2/18/20 12:11 PM, Marcel wrote: Hello! Say I have a struct where every member function can either be static or not depending on a template parameter. Is there a simple way to do this? Like, for example: struct Foo(Condition) { static if (Condition) static: void Bar() {} void Baz() {} } Since D conditional compilation must always be a valid declaration or statement, you cannot do something like this. The closest you can do is to use mixins, which means you have to write everything inside strings. It has been proposed quite a few times to have a way to enable/disable attributes based on a compile-time boolean. But it's never come close to getting included. -Steve
Re: Conditional Attributes
On Tuesday, 18 February 2020 at 17:11:55 UTC, Marcel wrote: Say I have a struct where every member function can either be static or not depending on a template parameter. Is there a simple way to do this? The best I can think of is: ``` mixin template maybeStatic() { void foo() { // implementation } } struct S(bool condition) { static if (condition) { static { mixin maybeStatic; } } else { mixin maybeStatic; } } ``` What do you need this for? It seems like an unusual situation to me.
Conditional Attributes
Hello! Say I have a struct where every member function can either be static or not depending on a template parameter. Is there a simple way to do this? Like, for example: struct Foo(Condition) { static if (Condition) static: void Bar() {} void Baz() {} }
Re: How to "Inherit" the attributes from a given callable argument?
On Thursday, June 13, 2019 3:49:04 AM MDT Jacob Carlborg via Digitalmars-d- learn wrote: > On 2019-06-12 22:42, Mek101 wrote: > > I didn't know it applied to templates other than lambdas. > > > > Thank you for your explanation. > > It applies to templates, lambdas (which basically are templates) and > nested functions. It also now applies to auto return functions, though that's a more recent change. - Jonathan M Davis
Re: How to "Inherit" the attributes from a given callable argument?
On 2019-06-12 22:42, Mek101 wrote: I didn't know it applied to templates other than lambdas. Thank you for your explanation. It applies to templates, lambdas (which basically are templates) and nested functions. -- /Jacob Carlborg
Re: How to "Inherit" the attributes from a given callable argument?
I didn't know it applied to templates other than lambdas. Thank you for your explanation.
Re: How to "Inherit" the attributes from a given callable argument?
On Wed, Jun 12, 2019 at 07:46:12PM +, Mek101 via Digitalmars-d-learn wrote: [...] > > public size_t indexOf(alias pred = "a == b", Range)(Range array) > > { > > alias predicate = unaryFun!pred; > > for(size_t i = 0; i < array.length; i++) > > if(predicate(array[i])) > > return i; > > return size_t.max; > > } > > Say that I may want to use the function in a @nogc scope, providing a > @nogc callable, but I also want to reuse the same code in managed > scope while passing a delegate: how can I apply the attributes of the > given callable to the function so that they're automatically > determined at compile time? [...] You don't need to do anything special; indexOf, as you declared it, is already a template function, so the compiler should automatically apply attribute inference to it. So if pred is @nogc, and the implementation of indexOf itself doesn't invoke the GC, the compiler should automatically infer @nogc for you. One safeguard that you might want to consider is to write a @nogc unittest, something like this: @nogc unittest { ... auto result = indexOf!(...)(...); ... } The @nogc annotation on the unittest ensures that as long as the pred argument to indexOf is @nogc, indexOf itself will also be @nogc. This prevents future changes from accidentally introducing GC dependent code in the implementation of indexOf, while at the same time not explicitly marking indexOf as @nogc (only the unittest is annotated, not the function itself) allows you to use it with GC-dependent predicates as well. T -- Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich Schubert
How to "Inherit" the attributes from a given callable argument?
I'll try to be straight. I have the following function: public size_t indexOf(alias pred = "a == b", Range)(Range array) { alias predicate = unaryFun!pred; for(size_t i = 0; i < array.length; i++) if(predicate(array[i])) return i; return size_t.max; } Say that I may want to use the function in a @nogc scope, providing a @nogc callable, but I also want to reuse the same code in managed scope while passing a delegate: how can I apply the attributes of the given callable to the function so that they're automatically determined at compile time? I know of std.traits.SetFunctionAttributes and std.traits.FunctionAttributes, but I have no idea on how to apply them to solve this. Perhaps I should declare indexOf as a template?
Re: Do @property attributes not allow postincrement operators
On Sunday, 14 April 2019 at 02:11:52 UTC, Mike Franklin wrote: On Sunday, 14 April 2019 at 01:54:39 UTC, Jamie wrote: Do @property attributes not allow postincrement operators? ... It's a long standing issue (going on 7 years old) ... I plan on getting to it, but there are other pressing things I'm trying to get out of the way. Mike Thanks Mike -- appears I didn't do a thorough enough search for this behaviour. Looking forward to it being implemented, cheers.
Re: Do @property attributes not allow postincrement operators
On Sunday, 14 April 2019 at 01:54:39 UTC, Jamie wrote: Do @property attributes not allow postincrement operators? import std.stdio; struct Foo { @property bar() { return 10; } @property bar(int x) { writeln(x); } } void main() { Foo foo; writeln(foo.bar); // actually calls foo.bar(); foo.bar = 10; // calls foo.bar(10); // following doesn't work foo.bar++; // would expect this to call foo.bar(foo.bar() + 1); // have to use: foo.bar = foo.bar + 1; writeln(foo.bar); } It's a long standing issue (going on 7 years old) https://issues.dlang.org/show_bug.cgi?id=8006 There's an implementation at https://github.com/dlang/dmd/pull/7079 It requires a DIP, which you can find at https://github.com/dlang/DIPs/pull/97 However, in preparing that DIP other issues were discovered with @property, so we need to create a DIP to fix those issues first. I plan on getting to it, but there are other pressing things I'm trying to get out of the way. Mike
Do @property attributes not allow postincrement operators
Do @property attributes not allow postincrement operators? import std.stdio; struct Foo { @property bar() { return 10; } @property bar(int x) { writeln(x); } } void main() { Foo foo; writeln(foo.bar); // actually calls foo.bar(); foo.bar = 10; // calls foo.bar(10); // following doesn't work foo.bar++; // would expect this to call foo.bar(foo.bar() + 1); // have to use: foo.bar = foo.bar + 1; writeln(foo.bar); }
Re: Get attributes of a field?
On 2019-04-02 15:23, Alex wrote: __traits(getAttributes, T) Requires a type and a field is unfortunately not a type ;/ enum attr; struct Foo { @attr int a; } void main() { alias a = __traits(getAttributes, Foo.a); } -- /Jacob Carlborg
Re: Get attributes of a field?
On Tuesday, 2 April 2019 at 13:36:47 UTC, Alex wrote: On Tuesday, 2 April 2019 at 13:23:37 UTC, Alex wrote: __traits(getAttributes, T) Requires a type and a field is unfortunately not a type ;/ I'd like to be able to get the attributes without having to instantiate the base type because that is problematic and I see no reason why it has to be instantiated to get CT values. Could you provide a full example for this issue and for your other message? That makes it easier to help you Kind regards Andre
Re: Get attributes of a field?
On Tuesday, 2 April 2019 at 13:23:37 UTC, Alex wrote: __traits(getAttributes, T) Requires a type and a field is unfortunately not a type ;/ I'd like to be able to get the attributes without having to instantiate the base type because that is problematic and I see no reason why it has to be instantiated to get CT values.
Get attributes of a field?
__traits(getAttributes, T) Requires a type and a field is unfortunately not a type ;/
Re: How to attach function attributes to delegate type?
On Wednesday, 27 February 2019 at 20:45:33 UTC, Alex wrote: On Wednesday, 27 February 2019 at 20:03:15 UTC, Q. Schroll wrote: For any type constructors like const, I can use ConstOf!T to get `T` with const attached. For a delegate/function type DG, e.g. int delegate(int), how can I get the @safe version of that type, i.e. int delegate(int) @safe? I tried alias SafeOf(DG) = DG @safe; but it didn't compile. The case is not @safe-specific; it's the same for all function attributes. At https://p0nce.github.io/d-idioms/ there is a demonstration for @nogc: ´´´ import std.traits; // Casts @nogc out of a function or delegate type. auto assumeNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) { enum attrs = functionAttributes!T | FunctionAttribute.nogc; return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; } ´´´ Didn't try this for other cases, however... When I need particular attributes, such as for a comparator, but also need to pass in a function as a template argument, one approach I've started to adopt is to only call this function from within a wrapper that has all the properties I want. For example: import std.stdio; class MyThing(T, alias LessF) { // This wrapper defines the conditions for a valid LessF. @safe @nogc private static bool less(in T t1, in T t2) { return LessF(t1, t2); } } void main() { MyThing!(int, (a, b) => a < b) a; // Compiles fine! MyThing!(int, (a, b) { writeln("Not @nogc!"); // Compiler error! return a < b; }) b; } The error looks like this, which is fairly readable too. onlineapp.d(6): Error: `@nogc` function `onlineapp.main.MyThing!(int, (a, b) { writeln("Not @nogc!"); return a < b; } ).MyThing.less` cannot call non-@nogc function
Re: How to attach function attributes to delegate type?
On Wednesday, 27 February 2019 at 20:03:15 UTC, Q. Schroll wrote: For any type constructors like const, I can use ConstOf!T to get `T` with const attached. For a delegate/function type DG, e.g. int delegate(int), how can I get the @safe version of that type, i.e. int delegate(int) @safe? I tried alias SafeOf(DG) = DG @safe; but it didn't compile. The case is not @safe-specific; it's the same for all function attributes. At https://p0nce.github.io/d-idioms/ there is a demonstration for @nogc: ´´´ import std.traits; // Casts @nogc out of a function or delegate type. auto assumeNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) { enum attrs = functionAttributes!T | FunctionAttribute.nogc; return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; } ´´´ Didn't try this for other cases, however...
How to attach function attributes to delegate type?
For any type constructors like const, I can use ConstOf!T to get `T` with const attached. For a delegate/function type DG, e.g. int delegate(int), how can I get the @safe version of that type, i.e. int delegate(int) @safe? I tried alias SafeOf(DG) = DG @safe; but it didn't compile. The case is not @safe-specific; it's the same for all function attributes.
Re: what are the rules for @nogc and @safe attributes inference?
On Fri, 30 Nov 2018 22:10:11 +, ikod wrote: > Thanks for explanation, got it. > > My case is actually > > interface I(K,V) > { > int get()(K); > } Interface functions must be abstract. Templated functions are implicitly final. Final things can't be abstract. If there's something about types K and V that determine whether you should be able to use the GC or not, you'll have to encode that explicitly.