Nicolas,
> On 28 Sep 2017, at 23:56, Nicolas Cellier
> <[email protected]> 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 <[email protected]>:
>
>
> > On 28 Sep 2017, at 18:50, Nicolas Cellier
> > <[email protected]> wrote:
> >
> >
> >
> > 2017-09-28 16:20 GMT+02:00 Sven Van Caekenberghe <[email protected]>:
> > 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 ?
>