I think I just stumbled onto something thanks to Elegantbeef in the discord. I 
can use closure, but more for fetching values from "parent"-Observables (to 
erase their types) than the observers.
    
    
    type Observable[SOURCE] = ref object
      value: SOURCE
      getValue: proc(): SOURCE {.closure.}
      observer: seq[proc(value: SOURCE)]
    
    proc newObservable[SOURCE](value: SOURCE): Observable[SOURCE] =
      Observable[SOURCE](
        value: value,
        getValue: proc(): SOURCE = value
      )
    
    type OperatorObservable[SOURCE, RESULT] = ref object
      getValue: proc(): RESULT {.closure.}
      transformer: proc(value: SOURCE): RESULT
      observer: seq[proc(value: RESULT)]
    
    proc newOperatorObservable[A, B, C](
      parent: OperatorObservable[A, B],
      transformer: proc(value: B): C
    ): OperatorObservable[B, C] =
      proc getValueClosure(): C =
        echo "Getting value from Operator Obs"
        let parentValue: B = parent.getValue()
        return transformer(parentValue)
      
      return OperatorObservable[B, C](
        getValue: getValueClosure,
        transformer: transformer,
        observer: @[]
      )
    
    proc newOperatorObservable[A, B](
      parent: Observable[A],
      transformer: proc(value: A): B
    ): OperatorObservable[A, B] =
      proc getValueClosure(): B =
        echo "Getting value from Source Obs"
        let parentValue: A = parent.getValue()
        return transformer(parentValue)
      
      return OperatorObservable[A, B](
        getValue: getValueClosure,
        transformer: transformer,
        observer: @[]
      )
    
    let obs = newObservable[int](5)
    let doubleObs = newOperatorObservable(
      obs,
      proc(x: int): int =
        echo "Double: ", x * 2
        return x * 2
    )
    let quadrupleObs = newOperatorObservable(
      doubleObs,
      proc(x: int): int =
        echo "Quadruple: ", x * 2
        return x * 2
    )
    let toStrObs = newOperatorObservable(
      quadrupleObs,
      proc(x: int): string = "I am now a string! "
    )
    
    echo quadrupleObs.getValue()
    echo toStrObs.getValue()
    
    
    Run

I'll see whether this will drive me into a corner somewhere, but I'm feeling 
optimistic about this approach.

Reply via email to