Checking function parameters in Phobos

Meta jared771 at gmail.com
Sun Nov 24 23:24:03 PST 2013


On Sunday, 24 November 2013 at 17:35:51 UTC, Simen Kjærås wrote:
>> I believe inout's point was this, though:
>>
>>    Validated!(isPositive, lessThan42, int) i = foo();
>>
>>    Validated!(isPositive, int) n = i; // Fails.
>>    Validated!(lessThan42, isPositive, int) r = i; // Fails.
>>
>> This is of course less than optimal.
>>
>> If a type such as Validate is to be added to Phobos, these 
>> problems need
>> to be fixed first.
>>
>>
>>> Or just pass a function that validates that the int is both 
>>> positive and
>>> less than 42, which would be much simpler.
>
> I've created a version of Validated now that takes 1 or more
> constraints, and where a type whose constraints are a superset 
> of
> another's, is implicitly convertible to that. Sadly, because of 
> D's lack
> of certain implicit conversions, there are limits.
>
> Attached is source (validation.d), and some utility functions 
> that are
> necessary for it to compile (utils.d).
>
> Is this worth working more on? Should it be in Phobos? Other 
> critique?
>
> Oh, sorry about those stupid questions, we have a term for that:
>
> Detroy!

Awesome, I was messing around with something similar but you beat 
me to the punch. A couple things:

- The function validated would probably be better named validate, 
since it actually performs validation and returns a validated 
type. The struct's name is fine.

- I think it'd be better to change "static if 
(is(typeof(fn(value)) == bool))" to "static if 
(is(typeof(fn(value)) : bool))", which rather than checking that 
the return type is exactly bool, it only checks that it's 
implicitly convertible to bool, AKA "truthy".

- It might be a good idea to have a version(AlwaysValidate) block 
in assumeValidated for people who don't care about code speed and 
want maximum safety, that would always run the validation 
functions. Also, it might be a good idea to mark assumeValidated 
@system, because it blatantly breaks the underlying assumptions 
being made in the first place. Code that wants to be rock-solid 
@safe will be restricted to using only validate. Or maybe that's 
going too far.

- Validated doesn't work very well with reference types. The 
following fails:

class CouldBeNull
{
}

bool notNull(T)(T t)
if (is(T == class))
{
	return t !is null;
}

//Error: cannot implicitly convert expression (this._value) of 
type inout(CouldBeNull) to f505.CouldBeNull
void takesNonNull(Validated!(CouldBeNull, notNull) validatedT)
{
}

- On the subject of reference types, I don't think Validated 
handles them quite correctly. This is a problem I ran into, and 
it's not an easy one. Assume for a second that there's a class 
FourtyTwo that *does* work with Validated:

	class FortyTwo
	{
		int i = 42;
	}
	
	bool containsFortyTwo(FortyTwo ft)
	{
		return ft.i == 42;
	}
	
	void mutateFortyTwo(Validated!(FortyTwo, containsFortyTwo) 
fortyTwo)
	{
		fortyTwo.i = 43;
	}
	
	auto a = validated!containsFortyTwo(new FortyTwo());
	auto b = a;
	//Passes
	assert(a.i == 42);
	assert(b.i == 42);
	mutateFortyTwo(a);
	//Fails
	assert(a.i == 43);
	assert(b.i == 43);

This is an extremely contrived example, but it illustrates the 
problem of using reference types with Validated. It gets even 
hairier if i itself were a reference type, like a slice:

	void mutateCopiedValue(Validated!(FortyTwo, containsFortyTwo) 
fortyTwo)
	{
		//We're not out of the woods yet
		int[] arr = fortyTwo.i;
		arr[0] += 1;
	}

         //Continuing from previous example,
         //except i is now an array
	mutateCopiedValue(b);
	assert(a.i[0] == 44);
	assert(b.i[0] == 44);

Obviously in this case you could just .dup i, but what if i were 
a class itself? It'd be extremely easy to accidentally invalidate 
every Validated!(FortyTwo, ...) in the program in a single swipe. 
It gets even worse if i were some class reference to which other, 
non-validated references existed. Changing those naked references 
would change i, and possibly invalidate it.


More information about the Digitalmars-d mailing list