72 type 73 ColumnKind* = enum 74 text, 75 integer, 76 float 77 Column* = object 78 case kind*:ColumnKind 79 of text: textVal*:string 80 of integer: integerVal*: int32 81 of float: floatVal*: float64 82 OneRow* = seq[Column] 83 proc oneRow*(stmt:Pstmt, maybeOneP:bool):(int8, OneRow) = 84 var rows:int8 = 0 85 var value:OneRow = @[] 86 while (nextRowAvailableP(stmt, RESET)): 87 for i in 0'i32..<s.column_count(stmt): 88 case s.column_type(stmt,i) 89 of SQLITE_TEXT: value.add(Column(kind:text, textVal: $s.column_text(stmt,i))) 90 of SQLITE_INTEGER: value.add(Column(kind:integer, integerVal: s.column_int(stmt,i))) 91 of SQLITE_FLOAT: value.add(Column(kind:float, floatVal: s.column_double(stmt,i))) 92 else: panic("oneRow:incorrect type returned") 93 rows = rows+1 94 stmt.reset 95 case rows 96 of 0: 97 if maybeOneP: 98 return (0, @[]) 99 else:
100 panic("oneRow: no rows returned") 101 of 1: 102 return (rows, value) 103 else: 104 panic("oneRow: query returned more than one row") 105
../nim_library/utilities.nim(98, 24) Error: type mismatch: got <tuple of (int, seq[empty])> but expected 'tuple of (int8, OneRow)' make: *** [makefile:9: composite_register] Error 1
I don't understand why assigning the null sequence to a variable of type OneRow is acceptable on line 85 but not acceptable as the OneRow component of the return value in line 98. I also don't understand why this compiled without error with the previous version of the compiler and not this one. If this is not a bug, please help me to understand why.
See the error message:
type mismatch: got <tuple of (int, seq[empty])> but expected 'tuple of (int8, OneRow)'
It seems to me that your return (0, @[]) is not automatically converted to 'tuple of (int8, OneRow)' like you would expect. See if changing that line to result = (0, @[]) solves the issue.
@LeuGim Thanks -- you got me focused on the first element of the tuple when I thought the issue was the second (the compiler message is ambiguous, since both types are different in the 'got' and 'expected' parts of the message).
I checked the language manual and the section on "Numerical constants" says "Literals without a type suffix are of an integer type, unless the literal contains a dot or E|e in which case it is of type float.". So the 0 I wrote is of type 'int'. Changing it to 0'i8 fixes the problem (it's surprising to me that the type suffixes are different from the types they denote). But changing this to
let zero:int8 = 0
return (zero, @[])
also works (compiles without error). Which led me to the manual section on Pre-defined integer types:
https://nim-lang.org/docs/manual.html#statements-and-expressions-type-conversions
This says that only widening conversions are implicit (and then in the immediately following table of examples, it says that
myInt16 + 34 # of type ``int16``
; I don't understand this; 34 is of type int, which is wider than int16, so why isn't the type of this expression int?)
But it then goes on to say that narrowing conversions are 'implicit' under certain circumstances, which are met by my case, as demonstrated by the assignment of 0 to zero (which narrows an int to an int8). So that leaves me with the question of why the 0 literal as the first element of the tuple was not converted to int8? As was apparently the case with the previous version of the compiler?
Changing it to 0'i8 fixes the problem (it's surprising to me that the type suffixes are different from the types they denote).
You can imitate it by 0.int8, it's compile-time converted.
So that leaves me with the question of why the 0 literal as the first element of the tuple was not converted to int8?
Because compiler doesn't treat it as a separate value, instead checks type compatibility for the whole l-value and r-value, i.e. of the type of the variable (result) and the type of the value you assign to it, two tuples.
The manual has an excelent section on type relations. Shortly:
Assignment compatibility requires types be implicitly convertible (and missing there, equal types are assignment-compatible of coarse too). isImplicitlyConvertible says about number conversions, nothing about tuples. So, by the manual, they should not be implicitly converted. Even not explicitly (the next code block).
Because compiler doesn't treat it as a separate value, instead checks type compatibility for the whole l-> value and r-value, i.e. of the type of the variable (result) and the type of the value you assign to it, two > tuples.
I understand that the compiler is doing the conversion in one case and not the other. That's obvious. What I question is whether it should be. If one can assign 0 to an int8 variable, then I would argue that one should be able to assign (0,"foo") to a (int8, string) variable.
For me it doesn't work with 0.18 either
I just checked and you are right. The only thing that I can think of is that I have not been using Nim for the project I am working on and have only experimented with it sporadically. I may have changed the routine in question and then, without compiling it, went off to something else. While that's not consistent with how I usually work, it's the only explanation I can think of, because I know for certain that a version of that file did compile with 0.18. I thought it was this version, but apparently not. In any case, my mistake.
If one can assign 0 to an int8 variable, then I would argue that one should be able to assign (0,"foo") to a (int8, string) variable.
I consider too, it would be more intuitive and is something one can expect. My answer was only about documentation being consistent with current compiler behaviour.