Thread overview
Subtypes with tighter constraints
Jan 01, 2019
Victor Porton
Jan 01, 2019
Alex
Jan 01, 2019
Neia Neutuladh
January 01, 2019
In Ada2012 there are "subtypes". Subtypes can have tighter constraints (such as type invariants) than their base types.

I have a struct X in D. Is it possible to define a type equivalent to X except that having tighter invariants?

As I understand if I derive Y from X, then it is no more X; that is I cannot use X (even provided it matches Y invariants) where I need Y. So in D it is impossible, right?

I think in D it's impossible, but want to be sure and so ask.

January 01, 2019
On Tuesday, 1 January 2019 at 14:05:43 UTC, Victor Porton wrote:
> In Ada2012 there are "subtypes". Subtypes can have tighter constraints (such as type invariants) than their base types.
>
> I have a struct X in D. Is it possible to define a type equivalent to X except that having tighter invariants?
>
> As I understand if I derive Y from X, then it is no more X;
1. As Ada is strongly typed, this is the same there, no?
2. You cannot derive structs in D. Therefore, I assume, that you meant that X and Y are classes.

> that is I cannot use X (even provided it matches Y invariants) where I need Y. So in D it is impossible, right?

It is possible, as invariants are inherited implicitly, see
https://dlang.org/spec/contracts.html#Invariants
paragraph 9.

´´´
import std.experimental.all;

void main()
{
	auto x = new X();
	auto y = new Y();
	x.d = 0.0;
	y.d = 1.0;
	x.fun;
	y.fun;
}

class X
{
	double d;

	invariant
	{
		assert(!d.isNaN);
	}
}

class Y : X
{
	invariant
	{
		assert(d > 0);
	}
}

void fun(T)(T t)
{
	assert(t);
}
´´´
January 01, 2019
On Tue, 01 Jan 2019 14:05:43 +0000, Victor Porton wrote:
> In Ada2012 there are "subtypes". Subtypes can have tighter constraints (such as type invariants) than their base types.
> 
> I have a struct X in D. Is it possible to define a type equivalent to X except that having tighter invariants?

In D, structs don't participate in inheritance. Classes do, but invariants aren't inherited; they're specific to the class in which the function is defined. (Which is probably a bug and I filed https://issues.dlang.org/ show_bug.cgi?id=19537.)

I see three ways to make this work today:

1. Use alias this to wrap the struct. Add invariants that deal with the
wrapped struct's fields.
2. Use compile-time reflection to copy the fields over, then manually copy
the invariants over and add more.
3. Use a class. Define a virtual function like 'doInvariant()`. Call it
from the base class's invariant{} block.

> As I understand if I derive Y from X, then it is no more X; that is I cannot use X (even provided it matches Y invariants) where I need Y. So in D it is impossible, right?

With classes, a derived class instance can be used anywhere you expect a base class instance. The reverse is not true.