Skip to content

Conversation

@ColmBhandal
Copy link
Owner

Description

Added toString() method so that validated types display the same as their raw types.

…aw object

Added a single test which confirms the toString works as expected for a positive integer
Otherwise, the error message reported upon validation would have been wrong
else
{
string valueAsString = value?.ToString() ?? "NULL";
string valueAsString = GetValueAsString(value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may be nitpicking, but if the value is immutable, shouldn't the string value be immutable too? In that case it can be calculated just once and stored on the class as a variable.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. We could create an immutable supertype that lazily stores the value for toString() and then delegates down to some abstract function to do the first calc

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe an immutable supertype is overkill... I'll just make it lazy here

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After coding up the change, twice, I realise that this isn't a good approach, in general. Even though the reference is immutable, doesn't mean the object data is. So toString() could return something different upon two successive calls from the same object. I attempted to rectify this by enforcing the generic parameter to be a struct, i.e. a value type, but this doesn't solve the above issue and it also disallows string, which is bad. So I think the best approach is to leave it as is, it's pretty cheap to call toString() anyway, and I'm sure the underlying value types, if they are indeed immutable, will have some optimisation there anyway, similar to what you suggest.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though the reference is immutable, doesn't mean the object data is

Doesn't this undermine the purpose of the validator?

If the data you are validating can change, it isn't enough to only validate it on construction because the value might change to something invalid.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this undermine the purpose of the validator?

Good point. Sub-classes of this abstract class should only use an immutable type as the generic parameter. That would be either a primitive value type or something like string. There's no way to enforce that with generics though.

Stepping back out to the original comment, which was the efficiency of toString(), the responsibility to make that efficient is on the owner of the immutable type itself. So this class shouldn't take that responsibility and get confused about its purpose.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that all makes sense. Ideally the validator class would be able to enforce that the types being validated are immutable, but it looks like there is no way to do it. In that case I think just documenting that the validator class is built around that assumption is enough.

@ColmBhandal
Copy link
Owner Author

ColmBhandal commented Jun 18, 2020 via email

@hctrdev
Copy link
Collaborator

hctrdev commented Jun 18, 2020

I've thought about it a bit more and I realised this applies to more than just immutable types. For example, a more general case is invariance of the validation condition. That is, if it can be proved that the initially validated condition is invariant under any operations on the wrapped object, then the condition is guaranteed to hold. For example, the wrapped object might be a type containing numbers and operations for incrementing those numbers only. Validating that this is positive at the outset guarantees positivity throughout. Things become even more complex when we notice that the invariance condition need not be the exact same as the initial condition: it can be weaker. For example, we might validate that the initial value of a field is exactly 1. And if only increment is allowed for that field, we have that it's always positive. That's a pretty trivial case and it's not clear that it would be useful in practice but there could be real cases out there where the initial condition is stronger eg because the stronger condition is simpler or more efficient to check than the invariance condition. For these reasons I think it's best leave it up to a user of this class to use it responsibly towards their own end rather than get prescriptive with documentation.

Yeah, you are right. The validator class could be used on more than just immutable objects. So that means you can only trust the validated types as far as you can trust the object you put into them. I would just call that out in the documentation.

@ColmBhandal ColmBhandal merged commit ce4011e into master Jun 18, 2020
@ColmBhandal ColmBhandal deleted the feature/validated-to-string branch June 18, 2020 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants