Wow, Alex nice investigation!

Thanks for looking into that.




On Wed, Oct 30, 2013 at 7:46 PM, Alex Vondrak <ajvond...@gmail.com> wrote:

> Let me preface by saying you generally want to avoid `execute` and
> `call`, except when implementing combinators
> (http://docs.factorcode.org/content/article-combinators.html).  As
> you've already seen, they might have some finicky behavior.  It's not
> quite the same level of antipattern as "eval is evil", but it's always
> felt similar to me.  Perhaps the following is a bit better:
>
> ```
> USING: arrays combinators formatting fry kernel sequences
> unicode.normalize ;
>
> : normalizations ( str -- norms )
>     {
>         [ nfc ]
>         [ nfd ]
>         [ nfkc ]
>         [ nfkd ]
>     } cleave 4array
>     [ [ "U+%04X" sprintf ] { } map-as ] map ;
> ```
>
> That said...
>
> The reason this issue was tripped was because of `nfc`---and probably
> the others, too, but `nfc` is the first one done in the `map`.
>
> `nfc` is defined like this:
>
> ```
> USING: unicode.normalize.private ;
> IN: unicode.normalize
> : nfc ( string -- nfc ) [ (nfd) combine ] with-string ;
> ```
>
> The `with-string` combinator that it uses is defined like this:
>
> ```
> USING: accessors kernel ;
> IN: unicode.normalize.private
> : with-string ( str quot -- str )
>     over aux>> [ call ] [ drop ] if ; inline
> ```
>
> Because the above word is inlined, `nfc` is "really" behaving like this:
>
> ```
> : nfc ( string -- nfc )
>     [ (nfd) combine ] over aux>> [ call ] [ drop ] if ;
> ```
>
> Thus, if the input string doesn't have an `aux` slot set, we don't do
> any computation because the `[ (nfd) combine ]` quotation just gets
> `drop`ped.  It's as though we defined it as just a no-op, like this:
>
> ```
> : nfc ( string -- nfc ) ;
> ```
>
> So, just take a look:
>
> ```
> IN: scratchpad "Factor" aux>> .
> f
> IN: scratchpad "\xF1" aux>> .
> B{ 0 0 }
> ```
>
> Because of the above, the call to `"Factor" nfc` becomes a no-op, and
> it *looks* to the Factor VM like `nfc` had the stack-effect `( -- )`.
> So, the `execute( -- )` doesn't raise an error in this example.
>
> To get really technical, I think the reason the VM thinks the
> stack-effect looks OK is because of how this primitive is implemented:
> https://github.com/slavapestov/factor/blob/master/vm/contexts.cpp#L274
>  Basically, the datastack before & after the call to `nfc` is exactly
> the same, so it thinks the stack effect was `( -- )`.  But with
> "\xF1", this isn't the case, and the error is thus caught.
>
> Hope that helps,
> --Alex Vondrak
>
> On Wed, Oct 30, 2013 at 3:24 PM, OwnWaterloo <ownwater...@gmail.com>
> wrote:
> > I'm new to Factor and don't know how to minimize the code while get
> > the similar behaviour. Sorry for that.
> > But thanks to the expressiveness and good libraries of Factor the code
> > won't be too long, I hope...
> >
> > Firstly, the primary goal is to normalize some unicode string.
> > Formating the result will make it more clear. And I also want to learn
> > the "Fried quotations".
> > So I use the three vocabularies:
> >
> >   IN: scratchpad USING: unicode.normalize formatting fry ;
> >   Loading resource:basis/formatting/formatting.factor
> >   Loading resource:basis/formatting/formatting-docs.factor
> >
> > Then the implement it with correct stack effect declaration in
> "execute(" :
> >
> >   IN: scratchpad : normalizations ( str -- norm )
> >    '[ _ swap execute( x -- x ) ] ! correct stack effect declaration
> >    { nfc nfd nfkc nfkd } swap map ! normalize str with four methods
> >    [ >array [ "U+%04X" sprintf ] map ] map ; ! make it more clear
> >
> > It gives me the expected results except the last two(but it maybe not
> > important to this question):
> >
> >   IN: scratchpad "Factor" normalizations .
> >   {
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >   }
> >   IN: scratchpad "\xF1" normalizations .
> >   {
> >       { "U+00F1" }
> >       { "U+006E" "U+0303" }
> >       { "U+00F1" }
> >       { "U+006E" "U+0303" }
> >   }
> >   IN: scratchpad "\x6E\u000303" normalizations .
> >   {
> >       { "U+00F1" }
> >       { "U+006E" "U+0303" }
> >       { "U+00F1" }
> >       { "U+006E" "U+0303" }
> >   }
> >   IN: scratchpad "\u01D160" normalizations .
> >   {
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >   }
> >   IN: scratchpad "\u01D158\u01D165\u01D16E" normalizations .
> >   {
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >       { "U+1D158" "U+1D165" "U+1D16E" }
> >   }
> >
> > But with the wrong stack effect declaration(actually I use the wrong
> > declaration first and the correct one latter during the study):
> >
> >   IN: scratchpad : normalizations ( str -- norm )
> >    '[ _ swap execute( -- ) ] ! wrong stack effect declaration
> >    { nfc nfd nfkc nfkd } swap map
> >    [ >array [ "U+%04X" sprintf ] map ] map ;
> >
> > The first case will pass:
> >
> >   IN: scratchpad "Factor" normalizations .
> >   {
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >       { "U+0046" "U+0061" "U+0063" "U+0074" "U+006F" "U+0072" }
> >   }
> >
> > And the rest will get an error:
> >
> >   IN: scratchpad "\xF1" normalizations .
> >   Quotation's stack effect does not match call site
> >   quot      [ \ nfc execute ]
> >   call-site ( -- )
> >
> >   Type :help for debugging help.
> >
> > The same thing will happen in "\x6E\u000303" "\u01D160"
> > "\u01D158\u01D165\u01D16E".
> >
> > I promise that I will not depend on this behaviour and will use the
> > correct stack effect declaration in real code.
> > I'm just curious that why "execute(" will check it in some cases but
> > won't in others?
> >
> > Thanks!
> >
> >
> ------------------------------------------------------------------------------
> > Android is increasing in popularity, but the open development platform
> that
> > developers love is also attractive to malware creators. Download this
> white
> > paper to learn more about secure code signing practices that can help
> keep
> > Android apps secure.
> >
> http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
> > _______________________________________________
> > Factor-talk mailing list
> > Factor-talk@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/factor-talk
>
>
> ------------------------------------------------------------------------------
> Android is increasing in popularity, but the open development platform that
> developers love is also attractive to malware creators. Download this white
> paper to learn more about secure code signing practices that can help keep
> Android apps secure.
> http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
> _______________________________________________
> Factor-talk mailing list
> Factor-talk@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/factor-talk
>
------------------------------------------------------------------------------
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
_______________________________________________
Factor-talk mailing list
Factor-talk@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to