Introducing with for Object members (property) cannot be assigned to when used with with
Opened this issue · 5 comments
Before
proc vmAdd(self: Computer) =
self.s.processor.memory3 = self.s.processor.memory1 + self.s.processor.memory2
self.s.processor.programCounter = self.s.processor.programCounter + 4
after
proc vmAdd(self: Computer) =
with self.s.processor:
memory3 = memory1 + memory2
programCounter = programCounter + 4
In the after code the s of the self in the with statement is underlined issue reported is template/generic instantiation of with
from here
memory3 and ProgramCounter are underlined with
'memory3' cannot be assigned to
'programCounter' cannot be assigned to
Please note that I in in the very early days of learning nim so its entirely possible I've made mistakes. The Advent of code problem to which the above code belongs compiles and gives the correct answers.
related code where with seems to work fine
type
OutputResponse* = enum
HaltOnOutput = 1,
ContinueOnOutput = 2,
type
Properties = ref object
actionOnOutput: OutputResponse
runHasCompleted: bool
input: seq[int64]
output: seq[int64]
type
State = ref object
newOutputReady: bool
processor: IntComputerProgramCounterFrame
type
Computer* = ref object
p: Properties
s: State
proc initProperties(): Properties =
result = new Properties
with result:
actionOnOutput = OutputResponse.HaltOnOutput
runHasCompleted = false
input = @[]
output = @[]
proc initState(): State =
result = new State
with result:
newOutputReady = false
processor = newIntComputerProgramCounterFrame()
proc initComputer*(): Computer =
result = new Computer
with result:
p = initProperties()
s = initState()
It's hard to deduce what your exact problem is from the snippets above because it does not include all type definitions, but if I complete it as below, everything works as expected:
import with
type
Processor = ref object
programCounter: int
memory1, memory2, memory3: int
Thing = ref object
processor: Processor
Computer = ref object
s: Thing
proc vmAdd(self: Computer) =
with self.s.processor:
memory3 = memory1 + memory2
programCounter = programCounter + 4
var c = Computer(s: Thing(processor: Processor()))
c.s.processor.memory1 = 1
c.s.processor.memory2 = 1
vmAdd(c)
echo c.repr
Could it be that you are passing objects to vmAdd, instead of ref objects? In this case you should define your proc to take a var
as argument like so:
proc vmAdd(self: var Computer)
...
I'd be glad to help you out with more details, but it would help if you could provide me with a full example with which I can fully reproduce your issue.
Please find attached the complete definitions of IntComputer and IntCOmputerProgramCounterFrame and the day2 code and input. I very much appreciate your taking the time to look at this issue.
IntComputer.zip
Ok, I admit with
is at fault here, as it does not properly understand your intentions here. It is a nice corner case here, so I'll try to see if I can get this to work.
Below is a standalone snippet that shows what is happening: the val=()
method is not properly handled by with
as it is not detected by the macro which generates the hidden access templates.
If I can't fix this I'm sure @PMunch can :)
Thanks for the report!
import with
type
Thing = ref object
hiddenVal: int
Box = ref object
thing: Thing
proc val(t: Thing): int =
t.hiddenVal
proc `val=`(t: Thing, v:int) =
t.hiddenVal = v
let box = Box(thing: Thing())
box.thing.val = 3
echo box.thing.val
with box:
thing.val = 4
echo thing.val
with box.thing:
val = 4
echo val # <---- BOOM
Hmm, this is tricky because there is no easy way that I know of to get procedures that take a given type.. I might be wrong, but this could potentially be super hard to fix.
That was my thought as well, Nim lacks the introspection to find out what procs or templates "belong" to a given type.