digitalmars.D.learn - Trait for "can be instantiated"?
- Ben Jones (30/30) May 09 2022 I have a struct template that takes an alias parameter and I'm
- =?UTF-8?Q?Ali_=c3=87ehreli?= (8/10) May 09 2022 Not answering that question but the 'is' expression seems to work in
- Ben Jones (4/14) May 09 2022 Using is(T) instead of isType!T also appears to be true for the
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/8) May 09 2022 I just found something that looked like a workaround. I don't know
- Salih Dincer (4/7) May 10 2022 I can't exactly use the is(T == char) or is(T : char) check. It
- Salih Dincer (19/20) May 10 2022 It gives an error when the exclamation mark is removed, I have no
- ag0aep6g (11/27) May 09 2022 `x` is a type, period.
- Ben Jones (9/19) May 10 2022 I'm writing a lexer and I'm using sumtype to store any of the
- H. S. Teoh (28/35) May 10 2022 A sum type in the case of token types is essentially the same thing as
- Ben Jones (5/8) May 10 2022 That's basically what sumtype is going to do for me, but
- H. S. Teoh (5/14) May 10 2022 Ah, I see what you're trying to do.
- Basile B. (28/36) May 11 2022 How about being more explicit in the UDA ?
- Ben Jones (11/13) May 11 2022 I think that could work but would require some major changes to
I have a struct template that takes an alias parameter and I'm trying to distinguish between type parameters and enum values. std.traits.isType works for this except for one edge case: ``` import std.traits; import std.stdio; struct S{} enum x; enum y = 5; struct Wrap(alias T) { static if(isType!T){ T value; //When t == x this doesn't work because `x` is opaque and has no default initializer } } void main() { pragma(msg, isType!x); //true pragma(msg, isType!y); //false Wrap!S ws; //OK Wrap!x wx; //error instantiating Wrap!y wy; //OK, because we the static if condition is false } ``` x is a "type" as far as isType is concerned (which makes sense to me), but I don't think you can ever declare a variable of that type since there's no way to initialize it... Is there a trait that can tell if you can initialize a variable of a certain type? The best I can think of is __traits(compiles, "T x;"), but it seems like it should be possible to do better?
May 09 2022
On 5/9/22 14:24, Ben Jones wrote:Is there a trait that can tell if you can initialize a variable of a certain type?Not answering that question but the 'is' expression seems to work in this case: static if(is (T)) { T value; } https://dlang.org/spec/expression.html#IsExpression Ali
May 09 2022
On Monday, 9 May 2022 at 21:58:59 UTC, Ali Çehreli wrote:On 5/9/22 14:24, Ben Jones wrote:Using is(T) instead of isType!T also appears to be true for the un-instantiate-able enum. Was your point just that I could replace isType!T with is(T)?Is there a trait that can tell if you can initialize a variable of a certain type?Not answering that question but the 'is' expression seems to work in this case: static if(is (T)) { T value; } https://dlang.org/spec/expression.html#IsExpression Ali
May 09 2022
On 5/9/22 20:52, Ben Jones wrote:Using is(T) instead of isType!T also appears to be true for the un-instantiate-able enum. Was your point just that I could replace isType!T with is(T)?I just found something that looked like a workaround. I don't know whether it is by design or by accident or whether this exercise exposes a compiler or language bug. Sorry... :) Ali
May 09 2022
On Tuesday, 10 May 2022 at 04:30:28 UTC, Ali Çehreli wrote:I just found something that looked like a workaround. I don't know whether it is by design or by accident or whether this exercise exposes a compiler or language bug. Sorry... :)I can't exactly use the is(T == char) or is(T : char) check. It isn't happening! But I still have a little more patience :) SDB 79
May 10 2022
On Tuesday, 10 May 2022 at 07:18:53 UTC, Salih Dincer wrote:But I still have a little more patience :)It gives an error when the exclamation mark is removed, I have no objections. But typing long instead of char also gives an error! ```d void main() { alias T = char; import std.traits; foreach(useableType; AllImplicitConversionTargets!(ulong)) { /* Except for four: long, float, double, real. The approval.//*/ assert(!is(T == useableType)); } // No errors! } ``` **Reference:** https://dlang.org/phobos/std_traits.html#AllImplicitConversionTargets SDB 79
May 10 2022
On 09.05.22 23:24, Ben Jones wrote:enum x; enum y = 5; struct Wrap(alias T) { static if(isType!T){ T value; //When t == x this doesn't work because `x` is opaque and has no default initializer } }[...]x is a "type" as far as isType is concerned (which makes sense to me), but I don't think you can ever declare a variable of that type since there's no way to initialize it... Is there a trait that can tell if you can initialize a variable of a certain type? The best I can think of is __traits(compiles, "T x;"), but it seems like it should be possible to do better?`x` is a type, period. You can use void initialization to declare values of types that don't have an `init` value: `x value = void;` As for an alternative to the brute force `__traits(compiles, ...)`, you can check if `T.init` is a thing: static if (is(typeof(T.init))) { T value; } I'm not sure if that's really better, though. By the way, what is your `Wrap` supposed to do with `x`? Treating it like `y` will likely fail, too, because `x` is not a value.
May 09 2022
On Tuesday, 10 May 2022 at 05:45:25 UTC, ag0aep6g wrote:`x` is a type, period. You can use void initialization to declare values of types that don't have an `init` value: `x value = void;` As for an alternative to the brute force `__traits(compiles, ...)`, you can check if `T.init` is a thing: static if (is(typeof(T.init))) { T value; } I'm not sure if that's really better, though. By the way, what is your `Wrap` supposed to do with `x`? Treating it like `y` will likely fail, too, because `x` is not a value.I'm writing a lexer and I'm using sumtype to store any of the token types. Some have values associated with them (like brackets and parens which are defined as `enum lparen = '('` or whatever) and some are just markers (keywords like 'if', which I'm trying to represent with just `enum if_token` ). The wrapper struct is there because I need a type for each one to use them as part of a sumtype and I only want to store the enum's value when it makes sense to.
May 10 2022
On Tue, May 10, 2022 at 03:26:28PM +0000, Ben Jones via Digitalmars-d-learn wrote: [...]I'm writing a lexer and I'm using sumtype to store any of the token types. Some have values associated with them (like brackets and parens which are defined as `enum lparen = '('` or whatever) and some are just markers (keywords like 'if', which I'm trying to represent with just `enum if_token` ). The wrapper struct is there because I need a type for each one to use them as part of a sumtype and I only want to store the enum's value when it makes sense to.A sum type in the case of token types is essentially the same thing as an enum value, implementation-wise. Sum types are implemented essentially as a discriminated union, which consists of a tag and a variant payload. The tag essentially behaves like an enum (and is in fact often implemented as such), which determines the interpretation of the payload. Using wrapper structs, etc., for this is IMO total overkill. Just use an enum for your token types. Something like this would suffice: enum TokenType { lparen, rparen, if_token, ... string_literal, } struct Token { TokenType type; union { string stringval; float floatval; ... // etc. } } T -- Two wrongs don't make a right; but three rights do make a left...
May 10 2022
On Tuesday, 10 May 2022 at 16:05:15 UTC, H. S. Teoh wrote:Using wrapper structs, etc., for this is IMO total overkill. Just use an enum for your token types. Something like this would suffice:That's basically what sumtype is going to do for me, but (hopefully) more safely. Also, the token types are "user defined," my lexer just grabs everything annotated with Token and passes those types/wrapped enums to sumtype.
May 10 2022
On Tue, May 10, 2022 at 04:10:26PM +0000, Ben Jones via Digitalmars-d-learn wrote:On Tuesday, 10 May 2022 at 16:05:15 UTC, H. S. Teoh wrote:Ah, I see what you're trying to do. T -- Why are you blatanly misspelling "blatant"? -- Branden RobinsonUsing wrapper structs, etc., for this is IMO total overkill. Just use an enum for your token types. Something like this would suffice:That's basically what sumtype is going to do for me, but (hopefully) more safely. Also, the token types are "user defined," my lexer just grabs everything annotated with Token and passes those types/wrapped enums to sumtype.
May 10 2022
On Tuesday, 10 May 2022 at 16:10:26 UTC, Ben Jones wrote:On Tuesday, 10 May 2022 at 16:05:15 UTC, H. S. Teoh wrote:How about being more explicit in the UDA ? The idea would be to associate the enum value to a type or not: ```d import std.traits; import std.stdio; struct Token(T); struct Token(T...) if (T.length == 0) { } Token!(string) enum str_tok; Token!(float) enum float_tok; Token!() enum lparen_tok; void main() { alias toks = getSymbolsByUDA!(mixin(__MODULE__), Token); static foreach (t; toks) {{ alias U = getUDAs!(t, Token); alias A = TemplateArgsOf!(U); static if (A.length) pragma(msg, "add a `" ~ A[0].stringof ~ "`for `" ~ t.stringof ~ "`"); else pragma(msg, "no SumType data needed for `" ~ t.stringof ~ "`"); }} } ```Using wrapper structs, etc., for this is IMO total overkill. Just use an enum for your token types. Something like this would suffice:That's basically what sumtype is going to do for me, but (hopefully) more safely. Also, the token types are "user defined," my lexer just grabs everything annotated with Token and passes those types/wrapped enums to sumtype.
May 11 2022
On Wednesday, 11 May 2022 at 12:29:05 UTC, Basile B. wrote:How about being more explicit in the UDA ? The idea would be to associate the enum value to a type or not:I think that could work but would require some major changes to my existing code. Also, I think I'd prefer: ``` Token{ enum lparen = '('; enum rparen = ')'; enum if_token; } ``` to what you suggested as a user of the library.
May 11 2022