I've just started learning Nim and I have two procedures- x takes a uint16 as an argument and y returns a uint16. If I do this:
let a = y()
x(a)
it works but this gives me a type mismatch:
x(y())
Is this that lazy execution that all of the kids are talking about these days? Is there a way to have the single line version properly do x with the return value of y? Thanks in advance.Could you provide a more complete code example? I'm having trouble replicating the problem
This here for example works:
proc y(): uint16 = 5.uint16
proc x(num: uint16): uint16 = 2*num
echo x(y())
echo y().x() # Alternative syntax for the same expression
The complete code is here: https://github.com/ForgetfulWasAria/nim_invaders
The read function is:
proc read*(s: Memory, address: var uint16): uint8 =
if address > s.capacity: address = address mod s.capacity
s.mem[address]
The other procedure is a getter/setter pair:
proc HL(s:Cpu): uint16 = (uint16(s.H) shl 8) + s.L
proc `HL=`(s: var Cpu, value: uint16): uint16 =
s.H = uint8(value shr 8)
s.L = uint8(value and 0xFF)
And here's where I used them:
proc M(s:Cpu): uint8 =
var address: uint16 = s.HL
s.memory.read(address)
That works but
s.memory.read(s.HL)
produces the type mismatch error:
A:\projects\nim\nim_invaders\src\cpu80.nim(126, 11) Error: type mismatch
Expression: read(s.memory, HL(s))
[1] s.memory: Memory
[2] HL(s): uint16
Expected one of (first mismatch at [position]):
[2] proc read(s: Memory; address: var uint16): uint8
Ahhh your code is running into "That thing ain't mutable" problem.
The value returned by HL is an immutable number as it comes out of HL. It is the assignment to a var variable that makes it mutable.
I don't think there's a way around this other than restructuring the code of read to not need to modify address.
So, basically there is one main question - do you rely on the behavior of address being mutated inside this proc outside of it? If yes, then you can create a non-var overload for your procedure and just call the original with the address created inside of that proc. If you don't rely on that behavior - just shadow the original.
Basically, option 1:
proc read*(s: Memory, address: var uint16): uint8 =
if address > s.capacity: address = address mod s.capacity
s.mem[address]
proc read*(s: Memory, address: uint16): uint8 =
var address = 0'u16
read(s, address)
Option 2:
proc read*(s: Memory, address: uint16): uint8 =
var address = 0'u16
if address > s.capacity: address = address mod s.capacity
s.mem[address]
If you need to mutate address to change it's value outside of procedure, then you should use var address.
But quickly glancing at your code, it seems you want to mutate argument only inside a procedure. Then you could do this little trick:
proc read*(s: Memory, address: uint16): uint8 =
var address = address
if address > s.capacity: address = address mod s.capacity
s.mem[address]
with this specific example mutation is unnecessary:
proc read*(s: Memory, address: uint16): uint8 =
s.mem[if address > s.capacity: address mod s.capacity else: address]