Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to return error without knowing value type (and vice versa) #28

Open
arnetheduck opened this issue Apr 12, 2023 · 2 comments
Open

Comments

@arnetheduck
Copy link
Owner

arnetheduck commented Apr 12, 2023

When creating a Result via err(x), the type of the value is not relevant until later - later being when the result is actually assigned to a variable of the Result type at which point the statically known type becomes dynamic.

It would be useful to be able to represent this "in-between" error value as being an error otherwise we always must know the full type at all times.

This becomes relevant in err itself that currently relies on type deduction of the result variable, a trick that only works in limited contexts.

A good example of this problem is or which cannot be combined with the self-deducing constructors:

proc f(): Result[float, int] =
  let v = Result[int, int].ok(42)
  # err deduces the "current" type to be `Result[int, int]` based on the 
  # `result` variable rather than on the context in which it's being evaluated
  # (in this case `or` with the `v` variable: the result of this operation should
  # be a `Result[int, int]`)
  let x = v or err(42)

Some ideas for how this could be solved:

  • err would use something else than result as a type source - how to inject that though?
  • err would return a magic type that converts to Result at the latest possible moment, automatically deducing T - since we know it's an error at this point, context can decide what T should be.
  • other solutions?
@arnetheduck
Copy link
Owner Author

Idea:

type Ok[T] = distinct T

proc `==`*[T0, E, T1](a: Result[T0, E], b: Ok[T1]): bool =
  a.isOk() and a.get() == T1(b)

@arnetheduck
Copy link
Owner Author

works!

type ErrMarker[E] = distinct E
template Err[E](v: E): ErrMarker[E] = ErrMarker[E](v)

template `or`*[T, E0, E1](self: Result[T, E0], other: ErrMarker[E1]): Result[T, E1] =
  let s = (self) # TODO avoid copy
  if s.oResultPrivate:
    when type(self) is type(other):
      s
    else:
      type R = Result[T, E1]
      when T is void:
        ok(R)
      else:
        ok(R, s.vResultPrivate)
  else:
    Result[T, E1].err(E1(other))

proc f(): Result[float, int] =
  let v = Result[int, int].ok(42)
  # err deduces the "current" type to be `Result[int, int]` based on the
  # `result` variable rather than on the context in which it's being evaluated
  # (in this case `or` with the `v` variable: the result of this operation should
  # be a `Result[int, int]`)
  let x = v or Err(42)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant