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.

Reply via email to