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 ?
> 


Reply via email to