On Sun, May 24, 2020 at 12:36 PM Alex Hall
OK, let's forget the colon. The point is just to have some kind of 'modifier' on the default value to say 'this is evaluated on each function call', while still having something that looks like `arg=<default>`. Maybe something like:
def func(options=from {}):
I worry so very little about this issue of mutable defaults that this discussion has trouble interesting me much. It's a speed bump for beginners, sure, but it's also sometimes a sort of nice (but admittedly hackish) way of adding something statefull to a function without making a class. On the other hand, I mostly thought it was cool before generators even existed; nowadays, a generator is more often a useful way to have a "stateful function" (yes, I know there are some differences; but a lot of overlap). The pattern: def fun(..., option=None): if option is None: option = something_else Becomes second nature very quickly. Once you learn it, you know it. A line of two of code isn't a big deal. But this discussion DOES remind me of something much more general that I've wanted for a long time, and that has had long discussion threads at various times. A general `deferred` or `delayed` (or other spellign) construct for language-wide delayed computation would be cool. It would also require rethinking a whole lot of corners. I think it would address this mutable default, but it would also do a thousand other useful things. Much of the inspiration comes from Dask. There we can write code like this simple one from its documentation: output = []for x in data: a = delayed(inc)(x) b = delayed(double)(x) c = delayed(add)(a, b) output.append(c) total = delayed(sum)(output) However, in that library, we need to do a final `total.compute()` to get back to actual evaluation. That feels like a minor wart, although within that library it has a purpose. What I'd rather in a hypothetical future Python is that "normal" operations without this new `delayed` keyword would implicitly call the .compute(). But things like operators or most function calls wouldn't raise an exception when they try to combine DelayedType objects with concrete things, but rather concretize them and then decide if the types were right. As syntax, I presume this would be something like: output = [] for x in data: a = delayed inc(x) b = delayed double(x) c = delayed add(a, b) output.append(c) total = sum(outputs) # concrete answer here. Obviously the simple example of adding scalars isn't worth the delay thing. But if those were expensive operations that built up a call graph, it could be useful laziness. Or for example: total = sum(outputs[:1_000_000) # larger list, don't compute everything -- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.