String validation with dedicated type


I am writing functions that expect string arguments containing only 'X', 'Y' and 'Z', such as "XYZXYZZYX". Rather than checking in each functions that the arguments are matched by a certain regex, it seems only natural to create a dedicated type, say XYZString. Then functions like

function f(s::XYZString) begin

are sure to operate on a good, “parsable” argument s when called as

s = XYZString("XYZYYXZ")

and I can remove validation and defensive coding from them.

So far I am failing to understand the proper way to construct this type.

  1. Can it be a simple type?
    Is there valid code in the vein of:
type XYZString String  # meaning XYZString is just a string under the hood
XYZString(s::AbstractString)::XYZString = ...
  1. Should it be some kind of type alias?

  2. Should it be a struct with an embedded string type implementing all the methods of the AbstractString interface?
    Like so:

struct XYZString <: AbstractString
   function XYZString(s::string)::XYZString
      if Set(s) ⊈ Set('X','Y','Z') throw(DomainError, "bad string") end

# many methods on XYZString to implement AbstractString, but which ones!?
# ...

It looks so verbose I cannot believe it is the right answer, plus I don’t know which methods are required and which are not, the docs are unclear to me, and finally I am bother by the necessity to embed a name value in a whole struct when all we need is just a string.

  1. How would this discussion extends for Vector{Char} instead of string?
    Namely, expecting arrays like ['X', 'Y', 'Z', 'Y'] instead of strings like "XYZY". Would it be easier?

It is similar to this question, though I find the answers do not help for beginner in Julia like me.

1 Like