Nim Compiler Version 0.13.0 (2016-01-19) [Windows: i386]
How would I store a reference to a procedure in a tuple:
Job = tuple[every:int, timescale:string, timestr:string, jobfunc:proc]
proc run(job: Job, jobfunc: proc): Job =
result = job
result.jobfunc = addr jobfunc
In the run proc jobfunc: proc gets accepted. In the tuple I get:
Error: 'proc' is not a concrete type.
So whats the type of proc?
[edit]
My ultimate goal is to pass a function with arbitrary parameters to run.
Atm I've managed to work around this by using an seq[string] but maybe one knows a more generic way.
type
Job = tuple[every:int, timescale:string, timestr:string, jobfunc: proc(args:seq[string]) {.gcsafe, locks: 0.}]
proc run(job: Job, jobfunc: proc,args:seq[string]= #[""] ): Job =
# ...
discard
proc myfunc(args:seq[string]) =
echo "hello from myfunc ", args
discard
schedule every(10).seconds.run(myfunc,args= #["foo","uggar"])
Storing a reference to proc accepting any combination of arguments in a non-generic way is not possible without losing compile-time type safety. If you really need it (in your case most likely you don't), you should use something like variant types with runtime type checks. However it looks like an overkill for your case. I don't think you have to store arguments user provides to his proc, but rather store a proc (closure) without arguments, allowing your user to wrap his arguments in a closure.
Basically, rewrite your run to smth like:
proc run(job: Job, jobfunc: proc()): Job =
# ...
Now your user would do:
proc myfunc(args:seq[string]) =
echo "hello from myfunc ", args
discard
var myArgs = #["foo","uggar"]
schedule every(10).seconds.run do(): # Do is a sugar for anonymous closure in this context
myfunc(myArgs)
There are different proc types, like proc: int, proc(x: int): string, in your case this should work:
type Job = tuple[every: int, timescale, timestr: string, jobfunc: proc()]
That specifies that jobfunc is a proc that takes no arguments and returns nothing.
Related
I (think I) need exec() to procedurally define variables for symbolic computation. The code searches for variables in an expression like 'x/y + z' and generates three variables,
x = sp.sympy('x'), y = sp.sympy('y'), z = sp.sympy('z')(for example).
When I run the code
for char in expr:
if char.isalpha():
exec('%s = sp.symbols("%s")' % (char, char))
print(type(char))
It works just as it should. print(type(char)) just checks if what I wanted to happen happens (it prints <class 'sympy.core.symbol.Symbol'> if it worked).
However, as I need this for a general expr, I need this inside a function. When I do this print(type(char)) outputs <class 'str'>, which means it didn't work.
Also, if I type print(type(char)) inside the exec I get a correct output.
Note: I know exec() is dangerous. I'm just going to use this to have an easier time writing lab reports.
I couldn't think of a way to get it into one line, but I believe this will work:
for char in expr:
if char.isalpha():
exec('%s = sp.symbols("%s")' % (char, char))
exec('temp_type = type(%s)' % char)
print(temp_type)
Alternatively using a dict approach may make it easier in the long run. It avoids the exec.
symbol_dict = dict()
for char in expr:
if char.isalpha():
symbol_dict[char] = sp.symbols(char)
print(symbol_dict[char])
I wrote a Nim procedure taking two objects as var parameters. They each are an object with an int field level. Before doing the real work of the procedure, I want to put the parameters in order by which has the larger level, so I do this:
proc subroutine(param1: var MyObject, param2: var MyObject) =
var large: ptr MyObject = param1.addr
var small: ptr MyObject = param2.addr
# If in wrong order by level, swap large and small
if large.level < small.level:
large = param2.addr
small = param1.addr
# The rest of the proc references, only variables large and small, e.g.,
large.level += 1
small.level += 2
This seems to work for my application, but I notice that in the Nim documentation, the ptr type is called "unsafe", and it is suggested to be used only for low-level operations. There's a "safe" reference type ref, and it is suggested to use ref unless you really want to do manual memory management.
I don't want to do manual memory management, and I want the Nim garbage collector to handle the memory for these parameters for me, but I don't see a way to get safe ref's to the two parameters.
I really want to be able to write the algorithm (which is significantly more complex than the simple code I showed) in terms of the variables large and small, rather than param1 and param2. Otherwise, if I can only reference parameters param1 and param2, without making these aliases for them, I'd have to copy and paste the same algorithm twice to separately handle the cases param1.level < param2.level and param1.level >= param2.level.
Is there a more idiomatic Nim way to do something like this, without using a ptr type?
There is no way you can turn a safe objecto into unsafe and viceversa, except by performing a copy of the object.
Normal variables are stored on the stack and thus will be destroyed when their function scope exists, but a reference can be stored into a global variable and accessed later. If this was possible, to make it safe, the compiler/language would need to know some way of extracting the variable from the stack so that it's still valid after its scope exists, or perform a copy manually behind your back, or some other magical thing.
That's also the reason why taking the address of a variable is unsafe. You can't guarantee its lifetime, because you could store that address somewhere else and try to use it later. However, in terms of memory guarantees, those variables should be kept alive at least for the time of your proc call, so it should be safe to use those address aliases within that proc without worrying.
That said, you could rewrite your code to use an intermediate proxy proc that performs the check and thus passes the correct variables in each slot. The intermediate proc guarantees that one of the variables will always be large, and you can avoid using unsafe references:
type
MyObject = object
level: int
proc subroutine_internal(large: var MyObject, small: var MyObject) =
assert large.level >= small.level
large.level += 1
small.level += 2
proc subroutine(param1: var MyObject, param2: var MyObject) =
if param1.level < param2.level:
subroutine_internal(param2, param1)
else:
subroutine_internal(param1, param2)
proc main() =
var
a = MyObject(level: 3)
b = MyObject(level: 40)
subroutine(a, b)
echo a, b
main()
type
MyObject = object
level: int
proc subroutine(param1, param2: var MyObject) =
if param1.level > param2.level:
swap(param1, param2)
echo param1.level
echo param2.level
var
p1 = MyObject(level: 7)
p2 = MyObject(level: 3)
subroutine(p1, p2)
p2.level = 13
subroutine(p1, p2)
Nim has the special swap() proc for that case. Var parameters are passed internally as pointers, so in parameter passing no copy is involved, and swap should do the copy as optimal as possible.
Of course, there can be cases where using ref objects instead of value objects can have advantages. Nim's references are managed pointers. You can find more information in the tutorials, and my one is located at http://ssalewski.de/nimprogramming.html#_value_objects_and_references.
def check_the_input_only_allows_digits_only(inp):
# A function for validating the input, the purpose of this is to let
# the user enter only digits.
if inp.isdigit() or inp is "" or inp == "\b" or inp is None:
return True
else:
return False
reg = creditor.register(check_the_input_only_allows_digits_only)
amount.config(validate = "key",validatecommand = (reg,"%P"))
I have understood that the function check_the_input_only_allows_digits_only is registered and for every character the user enters, the function is called and the input is validated. But why is the .register required, couldn't the function be called without .register every time the user enters something? What exactly is happening beneath the hood?
The important thing to know is that Tkinter is just a thin wrapper around an embedded Tcl interpreter. That means there are sometimes small compromises due to fundamental differences in the two languages.
The Tcl Way
When doing input validation in Tcl you specify a Tcl script rather than just a callable function. Tcl will scan the code for special character sequences (such as %P, %S, etc), and substitute them with information about the data to be validated.
When written in Tcl your code might look something like this:
entry .amount -validate key -validatecommand {
expr {[string is int %P] || [string length %P]==0}
}
Or, using a Tcl function:
proc check_the_input_only_allows_digits_only {P} {
expr {[string is int P] || [string length P] == 0}
}
entry .amount \
-validate key \
-validatecommand {check_the_input_only_allows_digits_only %P}
The Python Way
Python doesn't have an easy way to pass around code as a string, and even if it did Tcl wouldn't understand it. Instead, in python you must pass a reference to a callable -- typically a reference to a function or method.
In order to pass in those special substitution characters where python expects a callable, you must create a Tcl procedure which acts as a proxy to your python function. This command is created when you call the register function.
proc = creditor.register(check_the_input_only_allows_digits_only)
amount.config(validate = "key", validatecommand = (proc,"%P"))
If you do not use these characters, you don't need to register the command. For example, the following code is a valid way to call a function that takes no parameters:
def check_the_input_only_allows_digits_only():
...
amount.config(validate = "key",validatecommand = check_the_input_only_allows_digits_only)
Of course, being passed the values for %P and the other special character sequences is what makes the validation function so powerful.
I want to get a List from repository and assert its contents.
In following code I get a warning that states that Object cannot be assigned to List
Is there any way to add better argument to handle such case?
myDomainObjectRepository.save(_) >> { arguments ->
final List<MyDomainObject> myDomainObjects = arguments[0]
assert myDomainObjects == [new MyDomainObject(someId, someData)]
}
To elaborate on Opals answer: There are two parts and a footnote in the docs that are relevant here:
If the closure declares a single untyped parameter, it gets passed the
method’s argument list:
And
In most cases it would be more convenient to have direct access to the
method’s arguments. If the closure declares more than one parameter or
a single typed parameter, method arguments will be mapped one-by-one
to closure parameters[footnote]:
Footnote:
The destructuring semantics for closure arguments come straight from
Groovy.
The problem is that you have a single argument List, and since generics are erased groovy can't decide that you actually want to unwrap the list.
So a single non-List argument works fine:
myDomainObjectRepository.save(_) >> { MyDomainObject myDomainObject ->
assert myDomainObject == new MyDomainObject(someId, someData)
}
or a List argument combined with a second, e.g., save(List domain, boolean flush)
myDomainObjectRepository.save(_, _) >> { List<MyDomainObject> myDomainObjects, boolean flush ->
assert myDomainObjects == [new MyDomainObject(someId, someData)]
}
So the docs are a little bit misleading about this edge case. I'm afraid that you are stuck with casting for this case.
Edit: You should be able to get rid of the IDE warnings if you do this.
myDomainObjectRepository.save(_) >> { List<List<MyDomainObject>> arguments ->
List<MyDomainObject> myDomainObjects = arguments[0]
assert myDomainObjects == [new MyDomainObject(someId, someData)]
}
The docs seems to be precise:
If the closure declares a single untyped parameter, it gets passed the method’s argument list
However I've just changed my spec that uses rightShift + arguments to accept a single type argument and it did work. Try it out.
I have a strategies expressed as generics in nim:
proc fooStrategy[T](t: T, ...)
proc barStrategy[T](t: T, ...)
I would like to create a lookup table for the strategies by name... so I tried:
type
Strategy*[T] = proc[T](t: T, ...)
let strategies* = toTable[string, Strategy[T]]([
("foo", fooStrategy), ("bar", barStrategy)])
This doesn't work -- the type declaration fails. If I were to get by that I could guess that the table of strategies would also have problems. Is there another way to do this? "T" is supposed to be "some 1D collection type" -- could be sequence, array, vector from blas, etc. I could add concrete strategies to the table for common collections, but I still have the problem with the function pointer, as
type
Strategy* = proc(t: any, ...)
let strategies* = toTable[string, Strategy]([
("foo-seq[int]", fooStrategy[int]), ...])
still has problems. Any suggestions?
There are multiple issues with your code:
Firstly, initTable does not take a list of items for the table. It only takes an initial size. You want to use toTable instead.
Secondly, you must explicitly set a value for the generic parameter T when creating a table, because at runtime, all generic parameters must be bound to a type.
Thirdly, the proc types have to exactly match, including pragmas on the proc. This one's tricky.
Here is a working example:
import tables
type
Strategy*[T] = proc(t: T) {.gcsafe, locks: 0.}
proc fooStrategy[T](t: T) = echo "foo"
proc barStrategy[T](t: T) = echo "bar"
let strategies* = toTable[string, Strategy[int]]([
("foo", fooStrategy[int]), ("bar", barStrategy[int])
])
For this example, I create a table with Strategy[int] values (you cannot have a table with Strategy[T] values as this is not a concrete type). I instantiate both fooStrategy and barStrategy with [int] to match the table type. I added {.gcsafe, locks: 0.} to the type definition. If this is omitted, you will get a compiler error:
test.nim(9, 49) Error: type mismatch: got (Array constructor[0..1, (string, proc (t: int){.gcsafe, locks: 0.})])
but expected one of:
proc (pairs: openarray[(string, Strategy[system.int])]): Table[system.string, Strategy[system.int]]{.gcsafe, locks: 0.}
As you see, the compiler tells you in the first line what it sees and in the third line what it expects. it sees procs with {.gcsafe, locks: 0.} because those pragmas are implicitly assigned to the procs defined above. The pragmas change the type, so to be able to assign those procs to Strategy[T], you have to define the same pragmas to Strategy[T].