It's likely the best way to achieve what you're after is to use distinct 
typing, so you can convert inbetween them:
    
    
    type
      State = enum
        sGas
        sLiquid
        sSolid
      
      ExperimentImpl[T] = object
        data: T
      Experiment[T; MaterialState: static State] = distinct ExperimentImpl[T]
    
    
    proc `=copy`[T](dest: var ExperimentImpl[T], source: ExperimentImpl[T]) 
{.error: "do not copy".}
    proc `=dup`[T](x: ExperimentImpl[T]): ExperimentImpl[T] {.error: "do not 
duplicate".}
    
    
    func initExperiment[T; MaterialState: static State](initialData: T): 
Experiment[T, MaterialState] =
      Experiment[T, MaterialState](ExperimentImpl[T](data: initialData))
    
    func `$`[T; MaterialState: static State](e: Experiment[T, MaterialState]): 
string =
      $MaterialState & " " & $ExperimentImpl[T](e).data
    
    
    
    func condense[T](e: sink Experiment[T, sGas]): Experiment[T, sLiquid] =
      Experiment[T, sLiquid](e)
    
    func deposit[T](e: sink Experiment[T, sGas]): Experiment[T, sSolid] =
      Experiment[T, sSolid](e)
    
    func evaporate[T](e: sink Experiment[T, sLiquid]): Experiment[T, sGas] =
      Experiment[T, sGas](e)
    
    func solidify[T](e: sink Experiment[T, sLiquid]): Experiment[T, sSolid] =
      Experiment[T, sSolid](e)
    
    func melt[T](e: sink Experiment[T, sSolid]): Experiment[T, sLiquid] =
      Experiment[T, sLiquid](e)
    
    func sublimate[T](e: sink Experiment[T, sSolid]): Experiment[T, sGas] =
      Experiment[T, sGas](e)
    
    
    
    proc main =
      var e = initExperiment[int, sGas](initialData = 42)
      echo e
      let e2 = e.condense()
      echo e2
      let e3 = e2.solidify()
      echo e3
      let e4 = e3.sublimate()
      echo e4
      let e5 = e4.deposit()
      echo e5
    
    
    if isMainModule:
      main()
    
    
    Run

Reply via email to