开发者

Random value bug in Io

开发者 https://www.devze.com 2023-04-12 04:38 出处:网络
I\'m writing a unit test framework that will supply random integers, booleans, characters, and strings to test functions.

I'm writing a unit test framework that will supply random integers, booleans, characters, and strings to test functions.

Github repo: IoCheck. Code in question:

genChar := method(
    Random value(128) floor asCharacter
)

genSeq := method(gen,
    len := Random value(100) floor

    0 to(len) map(i,
        gen()
    )
)

genString := method(
    genSeq(genChar) join
)

# below always has same genChar    
"Random string: #{genString}" interpolate println

genSeq should generate a random sequence of 0 to 99 elements, using a generator function to populate the sequence. For some reason, when genChar is passed (see the genString 开发者_开发百科call in example.io), genSeq returns the exact same element in all positions.


The argument you pass genSeq is evaluated before calling it.

NB. Unlike languages like Python or Javascript, parenthesis aren't used to call the method and instead in Io its used to send messages to the method. Thus gen and gen() are the same because in Io methods are always called when used. You can access the method without calling it by using getSlot

NB. This link to a comment on Hacker News may help: http://news.ycombinator.com/item?id=1539431


One solution is to pass a block() (anonymous function) instead and then call it from within genSeq:

genSeq := method (gen,
    len := Random value(100) floor

    0 to(len) map(i, gen call)       // <= gen call  ie. call the block
)

genString := method (
    genSeq( block(genChar) ) join    // <= wrapped in a block()
) 

Another alternative is to pass a sequence (string) and run perform on it:

genSeq := method (gen,
    len := Random value(100) floor

    0 to(len) map(i, perform(gen))   // run string as method
)

genString := method (
    genSeq( "genChar" ) join         // method name is a sequence
)

And another alternative is to lazy evaluate the argument:

genSeq := method (                        // no defined parameters.  Lazy time!
    len := Random value(100) floor

    0 to(len) map(i, call evalArgAt(0))   // <= arg is evaluated here!
)

genString := method (
    genSeq( genChar ) join
)


BTW... to avoid control characters I also did this change (couldn't find doc for Random object but below was a random guess and it worked!).

genChar := method(
    Random value(33, 128) floor asCharacter
)
0

精彩评论

暂无评论...
验证码 换一张
取 消