Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I cause lazy evaluation of an expression?

I am trying to define an object master whose attribute/method decide can be called with an expression ex, but evaluation of that expression is postponed until some logic in decide asks for it (and it may even not do so). So, in code like this:

master.decide(ex)

it should be possible for ex to remain unevaluated if the logic in decide says so. In the code, ex stands for "arbitrary expression supplied by the client of my library." It can be as simple as 1 + 2 (where I wouldn't really care about lazy evaluation) to as complex as do_http_request().delete_record_from_database() (where I certainly do care).

Is such a thing possible? I am flexible on the syntax side, so if a solution exists which has to involve extra operators etc. around ex, I can consider it. But I would like ex to remain an expression.

I was thinking about (ab)using short-circuiting operators like and and or, but there doesn't seem to be a way to make those return something other than a boolean value.

The best I could come up with is wrapping ex in a lambda:

master.decide(lambda: ex)

def decide(ex):
  if decide_to_do_it():
    result = ex()
    somehow_use(result)

Or passing it as a string and using eval:

master.decide('ex')

def decide(ex):
  if decide_to_do_it():
    result = eval(ex)
    somehow_use(result)

(Yes, this one would have scoping issues).

Is there perhaps a magic function, trick, or something else which would allow me to keep ex as a plain expression?

like image 456
Angew is no longer proud of SO Avatar asked Feb 04 '16 08:02

Angew is no longer proud of SO


2 Answers

You can define a coroutine using yield here

def decide():
  ex=yield()
  if ex:
     result = ex()
     somehow_use(result)

master=decide()
next(master)
master.send(ex1)
master.send(ex2)
like image 188
vks Avatar answered Oct 10 '22 23:10

vks


You can pass a callable, just a function without arguments that is called when the expression needs to be evaluated.

Your lambda is one way to make such a callable, but you could just as easily pass a normal function or an instance method or whatever.

That's is the perfectly normal way to do it.

like image 29
RemcoGerlich Avatar answered Oct 10 '22 23:10

RemcoGerlich