Nicolas, > On 28 Sep 2017, at 23:56, Nicolas Cellier > <nicolas.cellier.aka.n...@gmail.com> wrote: > > Hi Sven, > for now it works because the context into which the block is executed still > has full access to the variables and receiver of outer context from which the > block is declared. > > But it's not necessarily the case in all dialects. > In VW for example, I get nil instead of foobar > #('loop on value 1 in nil' 'loop on value 2 in nil' 'loop on value 3 in nil') > > This is because the optimized block has its own method (a CompiledBlock) and > a restricted context (a BlockContext). > The receiver is the BlockClosure and this closure has no copiedValues from > the outerContext and an outerContext set to nil because some analyzer in the > compilation phase thought the closure would never access the outerContext (no > return to outerContext) nor any of its variable. > > Once we'll have clean blocks - depending on the implementation - things might > change in Pharo too. > But we must ask Clement on this subject (I add not taken time to check the > implementation he proposes).
I think I understand: you basically say that the compiler could remove/optimise away local/temp variables if it decides they are not used, hence accessing them dynamically will fail. This could be compiler/dialect specific. That being said, such behaviour would also make the debugger look strange (assigned local/temp is in the source code but not in the context). In Pharo, even the following (currently) works fine: [ :x :y | '{x}+{y}={x+y}' interpolate ] value: 7 value: 8. Sven > 2017-09-28 19:03 GMT+02:00 Sven Van Caekenberghe <s...@stfx.eu>: > > > > On 28 Sep 2017, at 18:50, Nicolas Cellier > > <nicolas.cellier.aka.n...@gmail.com> wrote: > > > > > > > > 2017-09-28 16:20 GMT+02:00 Sven Van Caekenberghe <s...@stfx.eu>: > > Hi, > > > > I got into a little office discussion about string interpolation as it is > > done in different programming languages. > > > > In Pharo we have String>>#format: which is pretty nice. It works as follows: > > > > | x y | > > x := 123. > > y := #foo. > > 'x={1} and y={2}' format: { x. y }. > > > > It is also possible to use a dictionary with keys, like this: > > > > | x y | > > x := 123. > > y := #foo. > > 'x={x} and y={y}' format: { #x->x. #y->y } asDictionary. > > > > But this is not true string interpolation as described in [ > > https://en.wikipedia.org/wiki/String_interpolation ]. The idea is to write > > the value generating expressions directly inside the strings. > > > > Since in Pharo we add features not by extending the syntax but by adding > > messages I wondered if it could be done for string interpolation. The goal > > is to make the following work: > > > > | x y | > > x := 123. > > y := #foo. > > 'It seems x equals {x} and y equals {y} while Pi is still {Float pi}' > > interpolate. > > > > => 'It seems x equals 123 and y equals foo while Pi is still > > 3.141592653589793' > > > > Here is the implementation I came up with: > > > > String>>#interpolate > > "Format the receiver by interpolating the evaluation of expressions > > in between curly brackets in the context of the sender as in the > > following 3 oneline examples. > > 'Today is {Date today}' interpolate. > > | x | x := 123. 'x equals {x} and pi equals {Float pi}' interpolate. > > 'In {#strings} you can escape \{ by prefixing it with \\' interpolate." > > > > | senderContext | > > senderContext := thisContext sender. > > ^ self class new: self size streamContents: [ :out | | stream | > > stream := self readStream. > > [ stream atEnd ] whileFalse: [ | currentChar | > > (currentChar := stream next) == ${ > > ifTrue: [ | expression result | > > expression := stream upTo: $}. > > result := Compiler new > > evaluate: expression in: senderContext to: nil notifying: nil > > ifFail: [ ^ nil ] logged: false. > > out nextPutAll: result asString ] > > ifFalse: [ > > currentChar == $\ > > ifTrue: [ stream atEnd ifFalse: [ out nextPut: stream next ] ] > > ifFalse: [ out nextPut: currentChar ] ] ] ] > > > > It is a hack that could certainly be improved. And there is of course an > > obvious security problem. > > > > Thoughts ? > > > > Sven > > > > > > Nice! > > The only objection I see is that it may fail in blocks if they don't know > > that they have to refer to outer context, especially once we have clean > > blocks > > Yes, there are probably some edge cases. Error handling is tricky too. > > > | outer | > > outer := 'foobar'. > > ^#( 1 2 3 ) collect: [:x | 'loop on value {x} in {outer}' interpolate] > > That example works for me in a Playground. How does it fail for you ? >