Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread Hlaaftana
I know this code isn't meant to be used, but the given answers for `var Child` 
were wrong to the point where I have to respond. We want the variable 
`self.child` not `child`. No need for templates or anything


type
  Child* = object
value: int
  
  Parent* = object
child: Child


proc set_value*(self: var Child, value: int): var Child {.discardable.} =
  self.value = value
  self

proc get_child*(self: var Parent): var Child =
  self.child = Child()
  self.child


var parent = Parent()

parent.get_child().set_value(10)

echo parent.child.value # 10


Run

Again, this isn't idiomatic code, just had to point it out.


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread Araq
Polluting your APIs in order to support "chaining" is a bad idea. Wait for 
[https://github.com/nim-lang/Nim/pull/13092](https://github.com/nim-lang/Nim/pull/13092)
 instead please.


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread solo989
working solution all in one snippet 


type
  Child* = ref object
value: int
  
  Parent* = ref object
child: Child


proc set_value*(self: var Child, value: int): var Child {.discardable.} =
  self.value = value
  return self

proc return_child(child : var Child) : var Child {.discardable.} =
  child

template get_child*(self : var Parent) : Child =
  var child = Child()
  self.child = child
  return_child(child)




var parent = Parent()

parent.get_child().set_value(10)


Run

However I would use @mratsim's solution instead unless you are using objects 
instead of ref objects.


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread ducdetronquito
Hey !

Thanks you for the quick answers !

As @solo989, just returning var Child like in the snippets below does not work 
has it triggers a compile error.


proc set_value*(self: var Child, value: int): var Child {.discardable.} =
self.value = value
return self


proc get_child*(self: var Parent): var Child {.discardable.} =
var child = Child()
self.child = child
return child

# Raises:
# Error: 'child' escapes its stack frame; context: 'child'; see 
https://nim-lang.org/docs/var_t_return.html


Run

Finally, @mratsim solutions works fine and make perfect sens :) 


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread SolitudeSF
you are returning value, not reference. change return type to var Child


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread mratsim
You don't need `var` in any of those procs because you are using ref objects 
and you are modifying the memory pointed to by the reference, not the reference 
itself.

i.e. this compiles


type
Child* = ref object
value: int

Parent* = ref object
child: Child


proc set_value*(self: Child, value: int): Child {.discardable.} =
self.value = value
return self


proc get_child*(self: Parent): Child {.discardable.} =
let child = Child()
self.child = child
return child


let parent = Parent()

parent.get_child().set_value(10)


Run


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread dawkot
get_child returns a Child, not a var Child


Re: How to chain prodecure calls that mutate a reference object ?

2020-01-19 Thread solo989
You need to make the return value var as well.


proc set_value*(self: var Child, value: int): var Child {.discardable.} =
self.value = value
return self


proc get_child*(self: var Parent): var Child {.discardable.} =
var child = Child()
self.child = child
return child


Run

However then var child escapes it's stack frame so I would normally make it a 
template instead. 


template get_child*(self : var Parent) : Child {.discardable.} =
  var child = Child()
  self.child = child
  child


Run

But the template doesn't work with discardable so combine both 


proc return_child(child : var Child) : var Child {.discardable.} =
  child

template get_child*(self : var Parent) : Child =
  var child = Child()
  self.child = child
  return_child(child)


Run