NetLogo / Python-Extension

Python extension for NetLogo
26 stars 15 forks source link

Passing in arguments without using py:set #16

Open arthurhjorth opened 4 years ago

arthurhjorth commented 4 years ago

Can we think of a good way to pass in arguments, à la LevelSpace maybe, so people don't have to write a line of code for each argument they want to pass in?

Maybe drawing on our anonymous function syntax (and maybe functionality?)

qiemem commented 4 years ago

What about py:call with following syntax?

(py:call "print" "hi") ; prints "hi"

(py:call "lambda x, y : np.array(x) + np.array(y)" [1 2 3] [4 5 6]) ; reports [5 7 9]

Probably need different ones for reporter vs command... py:call vs py:callreport?

lambda makes this pretty flexible, but unfortunately, Python's lambda also has some pretty severe limitations. What do you think?

arthurhjorth commented 4 years ago

I think that looks good, but I wonder if it is limited to lambdas and functions relying only on positional arguments then but not keyword arguments. I've tried to play around with it, but I haven't gotten it to work yet. Maybe I am missing something obvious, though.

An alternative is for these primitives to take an anonymous function that does the variable assignment, maybe? Like

py:run [ x -> "a_function(varname=x)"]

How does that look to you?

One question: why the different primitive? Could this not just build top of py:run and py:runresult?

arthurhjorth commented 4 years ago

Alternatively, we could do the syntax you suggested, but include the ability to pass in a list with name and value for keyword arguments?

(py:call "afunction" arg1 arg2 ["keyword" value])

Ideally we could find a way to write code that looks more like python, though. I can see how this works, but it would be nicer to just be able to inject them into a string of actual python code... somehow. Or maybe I am putting too much weight on that, and this is totally fine?

qiemem commented 4 years ago

An alternative is for these primitives to take an anonymous function that does the variable assignment, maybe?

Unfortunately, that doesn't work as the Python and NetLogo valid variable names are pretty different (in particular, can't uses dashes in Python).

Also, this would do pretty much exactly the same thing as using Python lambdas, but using Python lambdas doesn't require any magic. Do you see an advantage of something like this over Python lambdas? Seems like just one lambda for another. With your example, Python lambdas would be:

(py:call "lambda x : a_function(varname = x)" 5)

(of course, you'd only do this is varname is keyword only or whatever)

One question: why the different primitive? Could this not just build top of py:run and py:runresult?

Unfortunately, I don't see a way to do that, since those already use variadic arguments to concatenate strings into multiple lines.

(py:call "afunction" arg1 arg2 ["keyword" value])

I'd be down for this, but you'd need to use the list reporter rather than the literal syntax most of the time, since you can't include arbitrary reporters in the literal syntax.

arthurhjorth commented 4 years ago

Unfortunately, that doesn't work as the Python and NetLogo valid variable names are pretty different (in particular, can't uses dashes in Python).

Yeah... I started realizing it wasn't a good idea after I posted it. That's another good reason it isn't.

Also, this would do pretty much exactly the same thing as using Python lambdas, but using Python lambdas doesn't require any magic. Do you see an advantage of something like this over Python lambdas? Seems like just one lambda for another.

Totally - I guess I was trying to move more of the coding style to the NetLogo end, and that's all that would accomplish. I'm not sure that's actually desirable in this extension. So definitely something I think is important, or something that would buy us anything special.

Unfortunately, I don't see a way to do that, since those already use variadic arguments to concatenate strings into multiple lines.

Ah, gotcha.

(py:call "afunction" arg1 arg2 ["keyword" value])

I'd be down for this, but you'd need to use the list reporter rather than the literal syntax most of the time, since you can't include arbitrary reporters in the literal syntax.

I like where py:call is going! I think this feature would be nice, especially given how many python libraries include functions that have keyword arguments. Without it, people would have to write their own positional versions of those existing functions just to then call the library functions correctly.

Good point about list! Sigh... nothing we can do about it though.

qiemem commented 4 years ago

I think this feature would be nice, especially given how many python libraries include functions that have keyword arguments. Without it, people would have to write their own positional versions of those existing functions just to then call the library functions correctly.

Still not sure... It's actually more verbose than the lambda version since you have to write out list. Also, not sure how the extension would distinguish keyword pairs a list argument.