Thread overview
What's the use of 'typeof','typeid','__traits','is' ?
Aug 24
user1234
6 days ago
IchorDev
August 24

Hello every kind and helpful D programmers, I need your help.

I've met two problems about getting types.
In D, we can use many keywords to get the type of an object, such as typeof,typeid,is.
However, I don't know the differences between them well. I also don't know how to use them in D...

And yesterday, I've met an actual problem. If I'm writing a math library(Actually I'm not, it's an example just like my case):

class MyReal{
    //...
}

class MyInt:MyReal{
    public cent value;
    this(string makeNum){
        //...
    }
    MyReal opBinary(string op)(MyReal another){
        //...
    }
}

class MyFloat:NyReal{
    public double value;
    //...
}

The code above has simplified. It defines some simple classes.

And now, I have a function:

import std.algorithm.searching;
MyReal is_int_or_float(string inputs){
    if(inputs.canFind('.'))
        return new MyFloat(inputs);
    else
        return new MyInt(inputs);
}

The is_int_or_float() function has also simplified.
Then I need to use another function to get the type of the result of is_int_or_float(), so I may write another piece of code like:

import std.stdio;
string inputing="3.14";
MyReal result=is_int_or_float(inputing);
if(/*?????*/){
    writeln(cast(MyInt)result);
}else{
    writeln(cast(MyFloat)result);
}

Then I met the problem: I don't know to use which tool to get the type of result. I've tried many ways but it didn't help.
And strangely, I've met two cases like these code above yesterday, but sometimes one writing method could work well, but another couldn't. That made me surprised.

Can you solve the problem? What are the use of those keywords? How to use them? Which I should use to fill in the /*?????*/ ? I'm waiting for you.

August 24

On Sunday, 24 August 2025 at 03:13:38 UTC, David T. Oxygen wrote:

>

Hello every kind and helpful D programmers, I need your help.

I've met two problems about getting types.
In D, we can use many keywords to get the type of an object, such as typeof,typeid,is.
However, I don't know the differences between them well. I also don't know how to use them in D...

typeof is evaluated at compile time and gives the type of an expression or symbol as seen by the compiler.

typeid is evaluated at runtime and gives the TypeInfo object containing information about an object's runtime type.

The difference between typeof and typeid can be seen in the following program:

class Example {}

void main()
{
    auto object = new Example;
    check(object);
}

void check(Object o)
{
    import std.stdio;

    writeln(typeof(o).stringof); // Object
    writeln(typeid(o).toString); // Example
}
August 24

On Sunday, 24 August 2025 at 03:29:30 UTC, Paul Backus wrote:

>

On Sunday, 24 August 2025 at 03:13:38 UTC, David T. Oxygen wrote:

>

Hello every kind and helpful D programmers, I need your help.

I've met two problems about getting types.
In D, we can use many keywords to get the type of an object, such as typeof,typeid,is.
However, I don't know the differences between them well. I also don't know how to use them in D...

typeof is evaluated at compile time and gives the type of an expression or symbol as seen by the compiler.

typeid is evaluated at runtime and gives the TypeInfo object containing information about an object's runtime type.

--
Thanks.
But I still don't know how to use is __traits.
And, how can I fill in /*?????*/? Can I use typeid(result)==MyInt? Or if the is keyword can do this?

August 24
On Sun, Aug 24, 2025 at 05:20:06AM +0000, David T. Oxygen via Digitalmars-d-learn wrote: [...]
> But I still don't know how to use `is` `__traits`.
[...]

Operations involving types, such as type comparisons, are usually done only inside an `is`-expression.  For example:

```
struct MyType { ... }	// concrete definition of type
alias MyAlias = MyType;	// an alias to a type

static assert(is(MyAlias == MyType));
```

Usually this is most useful inside template functions that take one or more types as compile-time arguments.  For example:

```
void myFunc(T)(T data) {
	static if (is(T == string)) {
		writeln("data is a string");
		string x = data;
		// ... handle string data
	} else static if (is(T : double)) {
		writeln("data is not a string, but implicitly converts to double");
		double d = data;
		// ... handle double data
	} else {
		static assert(0, "don't know how to handle type: " ~ T.stringof);
	}
}
```

For more information, see:

	https://wiki.dlang.org/Is_expression


> And, how can I fill in `/*?????*/`? Can I use `typeid(result)==MyInt`? Or if the `is` keyword can do this?

You'd write this as:

```
is(typeof(result) == MyInt)
```

if the type must be exactly MyInt, or

```
is(typeof(result) : MyInt)
```

if the type may be something else that implicitly converts to MyInt.


T

-- 
Once bitten, twice cry...
August 24
On Sunday, 24 August 2025 at 08:25:56 UTC, H. S. Teoh wrote:
> On Sun, Aug 24, 2025 at 05:20:06AM +0000, David T. Oxygen via Digitalmars-d-learn wrote: [...]
>> But I still don't know how to use `is` `__traits`.
> [...]
>
> Operations involving types, such as type comparisons, are usually done only inside an `is`-expression.  For example:
>

I would have more described that as a "tool for static introspection".

I think that instead of `typeof()` D could have `__traits(type,arg)`.
August 24

On Sunday, 24 August 2025 at 08:25:56 UTC, H. S. Teoh wrote:

>

On Sun, Aug 24, 2025 at 05:20:06AM +0000, David T. Oxygen via Digitalmars-d-learn wrote: [...]

>

But I still don't know how to use is __traits.
[...]

Operations involving types, such as type comparisons, are usually done only inside an is-expression. For example:

struct MyType { ... }	// concrete definition of type
alias MyAlias = MyType;	// an alias to a type

static assert(is(MyAlias == MyType));

Usually this is most useful inside template functions that take one or more types as compile-time arguments. For example:

void myFunc(T)(T data) {
	static if (is(T == string)) {
		writeln("data is a string");
		string x = data;
		// ... handle string data
	} else static if (is(T : double)) {
		writeln("data is not a string, but implicitly converts to double");
		double d = data;
		// ... handle double data
	} else {
		static assert(0, "don't know how to handle type: " ~ T.stringof);
	}
}

For more information, see:

https://wiki.dlang.org/Is_expression

>

And, how can I fill in /*?????*/? Can I use typeid(result)==MyInt? Or if the is keyword can do this?

You'd write this as:

is(typeof(result) == MyInt)

if the type must be exactly MyInt, or

is(typeof(result) : MyInt)

if the type may be something else that implicitly converts to MyInt.

--
Thank you very much. But I made the result a MyReal object. And the typeof is a compile-time keyword. So can I get the expected answer at runtime? I'm afraid that is(typeof(result) == MyInt) will never be true.

August 24

On Sunday, 24 August 2025 at 03:13:38 UTC, David T. Oxygen wrote:

>

The is_int_or_float() function has also simplified.
Then I need to use another function to get the type of the result of is_int_or_float(), so I may write another piece of code like:

import std.stdio;
string inputing="3.14";
MyReal result=is_int_or_float(inputing);
if(/*?????*/){
    writeln(cast(MyInt)result);
}else{
    writeln(cast(MyFloat)result);
}

Then I met the problem: I don't know to use which tool to get the type of result. I've tried many ways but it didn't help.
And strangely, I've met two cases like these code above yesterday, but sometimes one writing method could work well, but another couldn't. That made me surprised.

You might be thinking about this the wrong way.

  1. The point of polymorphism is not to care about the type. You define the interface you need on the base type, and use that. Then the virtual functions naturally go to the right place.
  2. casting is the way to confirm the type (to a degree). A cast from one object to another is a dynamic cast, and will return null if the type does not match.
>

Can you solve the problem? What are the use of those keywords? How to use them? Which I should use to fill in the /*?????*/ ? I'm waiting for you.

To answer your specific query, I have 2 solutions. First, you can check that the TypeInfo (the D RTTI structure) is the same as the one you expect. Otherwise, you can cast the type to each leaf and see if it is not null.

// solution 1: (preferred)
if(auto r = cast(MyInt)result){
    writeln(r);
}else if(auto r = cast(MyFloat)result){
    writeln(r);
}

// solution 2:
if(typeid(result) is typeid(MyInt)){
    writeln(cast(MyInt)result);
}else{
    writeln(cast(MyFloat)result);
}

Solution 2 does not work if you have a deeper hierarchy. For example, if result is a derivative of MyInt, then solution 1 would succeed, whereas solution 2 would fail.

As a further note, I know this is a toy example. But Object.toString is a virtual function. For this exercise, you really should just overload toString and writeln(result).

-Steve

August 25

On Sunday, 24 August 2025 at 14:40:36 UTC, Steven Schveighoffer wrote:

>
// solution 1: (preferred)
if(auto r = cast(MyInt)result){
    writeln(r);
}else if(auto r = cast(MyFloat)result){
    writeln(r);
}

// solution 2:
if(typeid(result) is typeid(MyInt)){
    writeln(cast(MyInt)result);
}else{
    writeln(cast(MyFloat)result);
}

--
Thank you. I've tried solution1. It can work well.

6 days ago

On Sunday, 24 August 2025 at 03:13:38 UTC, David T. Oxygen wrote:

>

The code above has simplified. It defines some simple classes.

And now, I have a function:

import std.algorithm.searching;
MyReal is_int_or_float(string inputs){
    if(inputs.canFind('.'))
        return new MyFloat(inputs);
    else
        return new MyInt(inputs);
}

This would be a great use-case for std.sumtype.SumType:

import std.sumtype: SumType, match;
alias Number = SumType!(double, long);

Number isIntOrFloat(string input){
	import std.algorithm.searching: canFind;
	import std.conv: to;
	if(input.canFind('.'))
		return Number(input.to!double());
	else
		return Number(input.to!long());
}

void main(){
	string input = "3.14";
	Number result = isIntOrFloat(input);
	import std.stdio: writeln;
	result.match!(
		(long x){ writeln("integral: ",x); },
		(double x){ writeln("floating: ",x); },
	);
}