Jump to page: 1 2
Thread overview
Trait for "can be instantiated"?
May 09
Ben Jones
May 10
Ben Jones
May 10
ag0aep6g
May 10
Ben Jones
May 10
Ben Jones
May 11
Basile B.
May 11
Ben Jones
May 09

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
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 10
On Monday, 9 May 2022 at 21:58:59 UTC, Ali Çehreli wrote:
> 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

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)?
May 09
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 10
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 10

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

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!

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
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
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
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.
« First   ‹ Prev
1 2