ducktype icon indicating copy to clipboard operation
ducktype copied to clipboard

Are recursive types supported?

Open rulatir opened this issue 4 years ago • 5 comments

Is it possible to define a type e.g. "segment" that is either a string, a number, or an array of segments (recursive definition)? If not, please consider it a feature request.

Something like:

const segment = ducktype.indirect();
segment.that = ducktype(String, Number, [segment]);

or even:

const segment = ducktype.recursive(self => ducktype(String, Number, [self]));

Basically I need to validate that all "leaves" of a non-flat array are of a particular union type. I cannot flatten the array before validating because it is nested in a bigger data structure that I want to validate as a whole (as opposed to picking these arrays out of it for flattening and validation), and the nesting structure within the array is meaningful.

rulatir avatar Jan 17 '21 03:01 rulatir

Thanks for your suggestion @rulatir .

I'm not sure whether I understand you correctly, but creating circular references in your data model doesn't sound as something you should do in general. Can you explain your use case a bit more?

josdejong avatar Jan 18 '21 17:01 josdejong

My use case is something like a parse tree of an arbitrarily deeply nested expression. It is impossible to express actual cyclic references in the DSL, so there is no risk that an object containing cyclic references would be passed to a validator of a self-referential type. My proposal would allow specifying the type of an object that might directly or indirectly refer to or contain other objects of the same type. I understand that a naïve implementation of such a validator will choke on actual reference cycles, but sometimes it is guaranteed that this will never be the case.

rulatir avatar Jan 18 '21 19:01 rulatir

I think you're right. Would be neat indeed to support recursive types.

I do like your second proposal a lot, this looks very clean:

ducktype.recursive(self => ducktype(String, Number, [self]));

Would you be interested in creating a pull request for this?

josdejong avatar Jan 20 '21 13:01 josdejong

I already have a naïve implementation working, but I have reservations about offering this footgun to the public; not without a clear warning in the docs, that goes without saying.

I'm thinking about the feasibility of cycle checking. A DFS variant capable of detecting/avoiding cycles requires passing some shared context around, so it would be a major change in the algorithm.

rulatir avatar Jan 20 '21 14:01 rulatir

Sounds good 👍

josdejong avatar Jan 20 '21 14:01 josdejong