[Python-ideas] code segments

spir denis.spir at gmail.com
Thu Feb 20 14:10:37 CET 2014


I often find myself needing to wrap little pieces of code into a whole "object" 
(programming element or value), sometimes with a name. I feel the same kind of 
lack as an FP programmer having to code in a language without function 
"objects"; and indeed the situation is very similar.

The cases where i need that in fact follow a schema, let's call it "event". In 
games, an event is usually something that happens in a particular situation: 
there is a logic like situation --> happening, an event is in fact the binding 
of 2 elements. We find something similar with automation (which also is 
event-driven) sequences: a tree of stages which are reached under a condition 
and each command a given action: condition --> action. More generally, one may 
find a kind of cause --> effect schema. An event can be conceptualised as a 
{cause effect} pair. But what are the pair's elements? And how to encode them in 
a program?

	monster'appears : Event{
	    cause : and monster.is'hidden (= character.pos (33 99))
	    effect :
	        monster.move 37 101
	        monster.groar 'fiercefully
	        monster.is'hidden :: false
	        character.scream
	}

The cause is conceptually a logical expression; but it can be arbitrarily 
complex --thus may require multiple statements if only for readability, also for 
debugging or other "meta" needs. Otherwise, it is like a proper function, with 
an output (here a logical value) and no effect. But it does not take any input! 
instead, any pieces of data it uses are present in the surrounding scope: they 
_must_ be there, if i may say by logical necessity.
The effect is an action, like a procedure that changes the world and computes no 
product. Similarly, it takes no input but finds its data in the outer scope.

Thus, we have 2 kinds of input-less procedures. Otherwise, the notion is 
somewhat like Ruby blocks I guess. This is also similar to the recently proposed 
"inline" functions on python-ideas (reason why cc to this list).

There may also be a relation to dynamic scoping, since such code segments in 
fact appear to take their input from the caller's scope: but it is not a 
_caller_, instead a kind of surrounding block and scope, like in case of 
inlining. I think _this_ kind of semantics, similar to inlining, is the actual 
value of dynamic scoping, and what we may miss with static scoping only and 
ordinary procedures only. We may need a way to have "reified" blocks of code 
executed in the surrounding scope as if they were explicitely written there, or 
inlined (or C-like macros).

Actual functions/procedures would be overkill, since there is no stack frame (or 
similar), thus all the typical "prologue" and "epilogue" of procedure calls is 
unneeded. We just need to jump there, wherever the code lies in memory, and come 
back. Or, inline à la C, or like C macros, but this in my view does not match 
the semantics.

What I'm considering is code segment "objects" like procedures but without:
1. input variables,
2. local scope,
3. call/return [0],
three related points in fact.

Even more generally, one may note ordinary "functions", in mainstream langs and 
FP alike, combine a number of properties, the ones listed above plus:
0. more basically, general notion of a block of code as programming element
4. in addition, possible output product, for a function-like code segment
(maybe I miss some)
For the present notion of code segments, all i need is 0, plus 4 in some cases. [2]

I'm not sure at all this is a good idea, however --but I like it and would 
regularly use it if available.

d

[0] With register save, new stack frame construction, param passing (prologue), 
etc, and undoing of all that.

[1] A static location would not be thread safe; the only other possibility I can 
think of is dynamic allocation on the heap: overkill.

A real alternative is _not_ passing the product back, but noting that at a low 
level, there are no functions, instead only actions that write somewhere. Eg:
     x := DIV y z
actually means:
     DIV x (y z)
(and in fact at an even lower level x is y, so we get "DIV x z")
Similarly, when part of a higher expression we need temp storage location, eg:
     a := SUM b (DIV c d)
requires:
     DIV temp (c d)
     SUM a (b temp)
Also:
     IF (EQUAL a b) THEN do-that
gives:
     EQUAL temp (a b)
     IF temp THEN do-that
Function-like code segments would take the place of explicit expressions here. 
For instance:
     a := segment-name
     a := SUM b segment-name
     if segment-name then do-that
Thus, a rewriting rule can get read of their output altogether, I guess.

[2] Detail: in a low-level language, it may be easy to do that: a pair of goto; 
but the instruction for jumping back must accept a _variable_ target, and the 
the forward one may also be variable at times. In assembly, it's jumping to 
given addresses, or even just setting the PC register (program counter); there 
is no issue of variable targets at this level, they're variable adresses in 
general, meaning pointers. The only issue is scope restriction on such jumps 
(whether and how to possibly jump into other memory segments). A final point is 
the output of function-like code segments: we may need a single, temporary stack 
slot for it [1]. All these issues are solved for ordinary procedures.





More information about the Python-ideas mailing list