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

Error "invalid declaration order" when mixing generic and specific methods #5325

Open
bluenote10 opened this issue Feb 2, 2017 · 4 comments

Comments

@bluenote10
Copy link
Contributor

bluenote10 commented Feb 2, 2017

Consider a type hierarchy, where the base type is generic, but certain subtypes are not generic by nature, like in this example:

type
  Iterator[T] = ref object of RootObj

  CachedIterator[T] = ref object of Iterator[T]
    s: seq[T]
  FileRowIterator = ref object of Iterator[string]

method collect*[T](i: Iterator[T]): seq[T] {.base.} =
  quit "to override"

method collect*[T](i: CachedIterator[T]): seq[T] =
  result = i.s

method collect*(i: FileRowIterator): seq[string] =
  result = @["1", "2", "3"]

proc newFileRowIterator(): Iterator[string] =
  result = FileRowIterator()

let it = newFileRowIterator()
discard it.collect()

There are multiple issues with this:

  • There is an error invalid declaration order; cannot attach 'collect' to method defined here: <pointing to first (base) definition>.
  • The compiler complains with a warning in the third definition: use {.base.} for base methods; baseless methods are deprecated [UseBase] which is probably not what is intended here, because it is a method of a subtype.
@bluenote10 bluenote10 changed the title Wrong warning when overloading generic base with specific type Error "invalid declaration order" when mixing generic and specific methods Feb 6, 2017
@bluenote10
Copy link
Contributor Author

A first suspect: Maybe the problem lies somewhere in inheritanceDiff. I noticed that sameMethodBucket gets an inheritance diff of +1 when calling it with the first/base collect as the first argument, and the third/specialized collect as second. From my understanding it looks like the inheritance diff should be -1. Getting the inheritance diff wrong could probably explain both issues.

@bluenote10
Copy link
Contributor Author

I have found a work-around by mixing the type and method definitions:

# First: generic types _only_ (specialized types must wait)
type
  Iterator[T] = ref object of RootObj

  CachedIterator[T] = ref object of Iterator[T]
    s: seq[T]

# ... with generic methods
method collect*[T](i: Iterator[T]): seq[T] {.base.} =
  quit "to override"

method collect*[T](i: CachedIterator[T]): seq[T] =
  result = i.s

# And only now: specialized types and their methods
type
  FileRowIterator = ref object of Iterator[string]
  RangeIterator = ref object of Iterator[int]

method collect*(i: FileRowIterator): seq[string] =
  result = @["1", "2", "3"]
method collect*(i: RangeIterator): seq[int] =
  result = @[1, 2, 3]

proc newCachedIterator[T](s: seq[T]): Iterator[T] =
  result = CachedIterator[T](s: s)
proc newFileRowIterator(): Iterator[string] =
  result = FileRowIterator()
proc newRangeIterator(): Iterator[int] =
  result = RangeIterator()

let it1 = newCachedIterator[int](@[1, 2, 3])
echo it1.collect()
let it2 = newFileRowIterator()
echo it2.collect()
let it3 = newRangeIterator()
echo it3.collect()

@mratsim
Copy link
Collaborator

mratsim commented Sep 29, 2017

Same issue/error messsage for me, had to exchange the order of two base methods to make the compiler happy.

type
  Gate[TT] = ref object {.inheritable.}
    # Base operator or layer
    # Inherit from it and add a forward and backward method.

  Node[TT] = ref NodeObj[TT]

  NodeObj {.acyclic.} [TT] = object
    # Store an operator/layer + its parent
    gate: Gate[TT]
    parents: array[2, Node[TT]]

  Context*[TT] = ref object
    ## Tape / Wengert list. Contains the list of applied operations or layers
    nodes: seq[Node[TT]]

  Variable*[TT] = object
    ## Wrapper for values
    tape: Context[TT]
    value: TT # TT should be a Tensor[T] or CudaTensor[T] or a scalar

method forward*[TT](self: Gate[TT], a, b: Variable[TT]): Variable[TT] {.base.} =
  raise newException(ValueError, "forward method is not implemented")

## Exchanging the order of forward and backward works ##############

method backward*[TT](self: Gate[TT], gradient: TT): array[2,TT] {.base.} =
  raise newException(ValueError, "backward method is not implemented")

proc newContext*(TT: typedesc): Context[TT] {.noSideEffect.} =
  ## Initialize a context (Tape / Wengert list)
  new result
  result.nodes = newSeq[Node[TT]]()

#############################################################
type AddGate {.final.} [TT] = ref object of Gate[TT]
  arity: int
  a_shape: seq[int]
  b_shape: seq[int]


method forward*[TT](self: AddGate[TT], a, b: Variable[TT]): Variable[TT] =
  return Variable[TT](tape: a.tape, value: a.value + b.value)

method backward*[TT](self: AddGate[TT], gradient: TT): array[2,TT] =
  result[0] = 1.TT
  result[1] = 1.TT

var ctx = newContext float32

@metagn
Copy link
Collaborator

metagn commented Nov 17, 2024

No compile time error anymore but doesn't give the right output and the compiler gives a warning generic methods are deprecated

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

No branches or pull requests

4 participants