Skip to content

Instantly share code, notes, and snippets.

@gmpreussner
Created February 14, 2015 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmpreussner/17d4c61216cb744e270e to your computer and use it in GitHub Desktop.
Save gmpreussner/17d4c61216cb744e270e to your computer and use it in GitHub Desktop.
Generic param in nested type resolve issue
# Suppose we have the following type for a rectangular array:
type
RectArray*[R, C: static[int], T] = distinct array[R * C, T]
var a23: RectArray[2, 3, int]
var a32: RectArray[3, 2, int]
echo "a23: ", a23.R, "x", a23.C
echo "a32: ", a32.R, "x", a32.C
# Output:
# a23: 2x3
# a32: 3x2
# Looking good. Let's add a proc:
proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
echo "transpose"
var t32 = a23.transpose
echo "t32: ", t32.R, "x", t32.C
# Output:
# t32: 3x2
# Everything is still OK. Now let's use the rectangular array inside another
# generic type:
type
Matrix*[R, C: static[int], T] = object
a*: RectArray[R, C, T]
var m23: Matrix[2, 3, int]
var m32: Matrix[3, 2, int]
echo "m23: ", m23.R, "x", m23.C, " (", m23.a.R, "x", m23.a.C, ")"
echo "m32: ", m32.R, "x", m32.C, " (", m32.a.R, "x", m32.a.C, ")"
# Output:
# m23: 2x3 (2x3)
# m32: 3x2 (3x2)
# Everything is still as expected. Now let's add the following proc:
proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
echo "transpose"
var x23: Matrix[2, 3, int]
var x32 = x23.transpose
echo "x23: ", x23.R, "x", x23.C, " (", x23.a.R, "x", x23.a.C, ")"
echo "x32: ", x32.R, "x", x32.C, " (", x32.a.R, "x", x32.a.C, ")"
# Output:
# x23: 2x3 (2x3)
# x32: 3x2 (2x3) <--- this is incorrect. R and C do not match!
@gmpreussner
Copy link
Author

Here is an example of how the seemingly cached generic parameters affect subsequent variable declarations:

type
  RectArray*[R, C: static[int], T] = distinct array[R * C, T]

proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
  echo "transpose"

var a23: RectArray[2, 3, int]
var a32 = a23.transpose

echo "a23.R = ", a23.R, ", a23.C = ", a23.C
echo "a32.R = ", a32.R, ", a32.C = ", a32.C

type
  Matrix*[R, C: static[int], T] = object
    a*: RectArray[R, C, T]

proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
  echo "transpose"

var m23: Matrix[2, 3, int]
var m32 = m23.transpose

echo "m23: ", m23.R, "x", m23.C, " (", m23.a.R, "x", m23.a.C, ")"
echo "m32: ", m32.R, "x", m32.C, " (", m32.a.R, "x", m32.a.C, ")"

var t32: Matrix[3, 2, int]   # adding this variable after the call to m32.transpose

echo "t32: ", t32.R, "x", t32.C, " (", t32.a.R, "x", t32.a.C, ")"

# Output:
# transpose
# a23.R = 2, a23.C = 3
# a32.R = 3, a32.C = 2
# transpose
# m23: 2x3 (2x3)
# m32: 3x2 (2x3)   <---- still wrong
# t32: 3x2 (2x3)   <---- but this is now wrong, too!

@gmpreussner
Copy link
Author

If we move the declaration of t32 BEFORE the call to transpose(), t32 will have the correct type:

type
  RectArray*[R, C: static[int], T] = distinct array[R * C, T]

proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
  echo "transpose"

var a23: RectArray[2, 3, int]
var a32 = a23.transpose

echo "a23.R = ", a23.R, ", a23.C = ", a23.C
echo "a32.R = ", a32.R, ", a32.C = ", a32.C

type
  Matrix*[R, C: static[int], T] = object
    a*: RectArray[R, C, T]

proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
  echo "transpose"

var t32: Matrix[3, 2, int]  # moved this variable before the call to m23.transpose

echo "t32: ", t32.R, "x", t32.C, " (", t32.a.R, "x", t32.a.C, ")"

var m23: Matrix[2, 3, int]
var m32 = m23.transpose

echo "m23: ", m23.R, "x", m23.C, " (", m23.a.R, "x", m23.a.C, ")"
echo "m32: ", m32.R, "x", m32.C, " (", m32.a.R, "x", m32.a.C, ")"


# Output:
# transpose
# a23.R = 2, a23.C = 3
# a32.R = 3, a32.C = 2
# t32: 3x2 (3x2)          <---- now correct!
# transpose
# m23: 2x3 (2x3)
# m32: 3x2 (2x3)          <---- still wrong, of course

@gmpreussner
Copy link
Author

The above problems seem to be specific to static[T] parameters. For reference, the following example works correctly:

import typetraits

type
  Foo*[A, B] = object
    a: A
    b: B

proc transpose[A, B](m: Foo[A, B]): Foo[B, A] =
  echo "transpose"

var aif: Foo[int, float]
var afi = aif.transpose

echo "aif: ", aif.A.name, " ", aif.B.name
echo "afi: ", afi.A.name, " ", afi.B.name

type
  Bar*[A, B] = object
    a*: Foo[A, B]

proc transpose[A, B](m: Bar[A, B]): Bar[B, A] =
  echo "transpose"

var mif: Bar[int, float]
var mfi = mif.transpose

echo "mif: ", mif.A.name, " ", mif.B.name, " (", mif.a.A.name, " ", mif.a.B.name, ")"
echo "mfi: ", mfi.A.name, " ", mfi.B.name, " (", mfi.a.A.name, " ", mfi.a.B.name, ")"

var tfi: Bar[float, int]

echo "tfi: ", tfi.A.name, " ", tfi.B.name, " (", tfi.a.A.name, " ", tfi.a.B.name, ")"


# Output:
# transpose
# aif: int float
# afi: float int
# transpose
# mif: int float (int float)
# mfi: float int (float int)
# tfi: float int (float int)

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