elm-community / typed-svg

Typed SVG library written for Elm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

More typesafe

gampleman opened this issue · comments

In SVG, many (if not most) attributes are specific to certain elements. This means that it is a programmer error if one uses an unsupported attribute on an element. It would make a lot of sense if that was a compile time error rather than either a runtime error or a silent failure.

I think using a phantom type approach would achieve that.

First, each element would need to list the attributes it supports in its type signature (there can be some that are grouped since everything supports them). For example:

polyline : 
    List 
        (Attribute 
            { points : Supported
            , pathLength : Supported
            , graphicalEvents : Supported
            , presentationAttributes : Supported
            }
           msg
        )
    -> List (Svg msg) -- not sure polyline can even have children!?
    -> Svg msg

The obvious disadvantage here is that the type signature is quite large, but on the other hand it is quite explicit about what you can pass in. The attributes would then look like this:

points : List (number, number) -> Attribute { a | points : Supported } msg

class : List String -> Attribute a msg -- class can go on any svg element, so no constraints here

onActivate : msg -> Attribute { a | graphicalEvents : Supported } msg -- this is part of a group, since these attributes always go together

The nice thing is that this provides high levels of safety, but no runtime overhead since all of this information is stripped out at compile time.

(Futhermore this approach could be used for values, so instead of having many constructors with prefixNone, one could simply have a none value).

The type signature being large is perhaps not such a problem - its length doesn't impose on the user of this API, right? And it can be helpful to the user of the API too, because its type shows what attributes are possible on each element.

Also, this change would likely not break existing code? If it is using correct attributes it should compile as before without change.

Yes at least for the attributes. If one would give the values (i.e. the various keywords and units) this treatment, then that would be a breaking change.