Menu

#3 switch instruction

open
nobody
None
5
2002-03-17
2002-03-17
Anonymous
No

Hi all,

I have used Dialect for two years now and I think
a "switch" instruction (or "select" if you prefer the
BASIC-style semantics) would be a nice thing to have
in Dialect. Processing all decisions
with "if...then...elseIf" structures is somewhat
laborious and clumsy.

Christian Lesage

Discussion

  • A.H. Banen

    A.H. Banen - 2002-03-17

    Logged In: YES
    user_id=423153

    Christian,
    I'd agree if switches or case statements weren't a source
    of errors when implemented badly. E.g. what should happen
    when the select doesn't find a match? Should nothing be
    executed or an otherwise clause? This must be decided
    before even thinking about implementation.
    So when you request a feature like a switch it would help
    if you would give some description of how you would like
    the switch to function so we can at least discuss about
    it :)

    In the mean time some suggestions you could use if you'd
    badly need to use a switch like functionality. Please don't
    consider it a solution, but instead more like an
    inspiration...

    Andr

    # A way a switch could be implemented as a function
    switch = func( val , fr )
    local v, s
    foreach v, s in fr
    if (v[1->3] = "ON:") and (eval(v[4->-1]) =
    val) then Interpret( s ); endif
    endforeach
    endfunc

    ## Using switch:

    x = "a"
    r = 100
    switch( x, {
    "ON:`r`":"print r, cr",
    "ON:`y`":"r = r + 1",
    "ON:`a`":"r = 0",
    "ON:`b`":"r = r -1"
    })

    print "R = ",r, cr

    x = 2
    r = 100
    switch( x, {
    "ON:1":"print r, cr",
    "ON:2":"r = r + 1",
    "ON:3":"r = 0",
    "ON:4":"r = r -1"
    })

    print "R = ",r, cr

    x = 'delta
    r = 100
    switch( x, {
    "ON:'alpha1":"print r, cr",
    "ON:'beta":"r = r + 1",
    "ON:'gamma":"r = 0",
    "ON:'delta":"r = r -1"
    })

    print "R = ",r, cr

    # Alternatively do the interpreting directly:

    Switchframe = {
    "'alpha1":"print r, cr",
    "'beta":"r = r + 1",
    "'gamma":"r = 0",
    "'delta":"r = r -1"
    }

    x = 'beta
    r = 100
    Interpret( Switchframe[ unparse(x) ] )

    print "R = ",r, cr

     
  • A.H. Banen

    A.H. Banen - 2002-03-18

    Logged In: YES
    user_id=423153

    Christian,
    I appears that the do-it-all frame data structure can be
    used to create a switch like assignment. This relies on
    three syntactically possible but somewhat awkward looking
    uses of function bodies, frame indexing and effecting a
    function call.
    Notice it is possible to use an anoymous function as a kind
    of block statement where 'func()' acts as a 'BEGIN BLOCK'
    and 'endfunc' as 'END BLOCK' where a 'block'is nothing more
    or less then a group of statements between BEGIN BLOCK and
    END BLOCK.
    Also it is possible to index an anonymous frame, e.g.
    x = "South" ; y =
    { "North":90, "West":180, "South":270, "East":360 }[ x ]
    Finally it is possible to call an anonymous function by
    appending () (or (<param_list>) ) to the function body or
    an expression returning this.
    As a result a frame based pseudo switch could look like:

    x = 'gamma
    r = 100

    switch = { # switch is here a dummy variable
    "'alpha1" :func(); print r, cr ; endfunc,
    "'beta" :func(); r = r + 1 ;
    endfunc,
    "'gamma" :func(); r = 0 ;
    endfunc,
    "'delta" :func(); r = r -1 ;
    endfunc
    }[ unparse(x) ]() # unparse needed to preserve the '
    of the symbol

    print "R = ",r, cr

    Based on a construction as shown above it would basically
    only :) need some syntactical rewrite rules to translate
    a 'real' switch statement to the frame based construction.
    It shows it does not need to be hard to implement a switch
    in Dialect.

    Andr

     
  • Nobody/Anonymous

    Logged In: NO

    Andr,

    Thank you for your suggestions. For now, the method I
    prefer is the one in which the code is directly
    intrepretated, since it allows the simulated "switch" to
    see the local variables of a function inside of its own
    clauses.

    Here's a little code snippet based on your suggestions that
    allows a no-match case to be executed :

    testFunc = func()
    y = 10
    x = 2

    toDo = {"1": "y = y + 1",
    "2": "y = y + 2",
    "other": "y = y + 3"}[unparse(x)]

    if not(toDo) then toDo = theFrame.other; endIf
    interpret toDo

    print y

    endFunc

    testFunc()

    By implementing the "switch" as a function, or by defining
    its clauses using anonymous functions, you loose the
    possibility of accessing the local variables of the
    function which uses the "switch".

    As for how I think a real "switch" should be implemented,
    well I think it should behave just like the "switch" of
    well known languages such as C or BASIC does, i.e. it
    shouldn't do anything if no match have been found, unless
    otherwise specified by a "no-match" instruction.

    For example, it might look like this :

    switch theName
    case "Mickey" :
    print "You're a mouse.",cr
    case "Goofy" :
    print "You're a dog.",cr
    oneof "Donald", "Huey", "Dewey", "Louie" :
    print "You're a duck.",cr
    other :
    print "You might be human.",cr
    endSwitch

    I hope this will give you a better idea of what I was
    thinking about.

    Christian

     
  • Nobody/Anonymous

    Logged In: NO

    Andr,

    Thank you for your suggestions. For now, the method I
    prefer is the one in which the code is directly
    intrepretated, since it allows the simulated "switch" to
    see the local variables of a function inside of its own
    clauses.

    Here's a little code snippet based on your suggestions that
    allows a no-match case to be executed :

    testFunc = func()
    y = 10
    x = 2

    toDo = {"1": "y = y + 1",
    "2": "y = y + 2",
    "other": "y = y + 3"}[unparse(x)]

    if not(toDo) then toDo = theFrame.other; endIf
    interpret toDo

    print y

    endFunc

    testFunc()

    By implementing the "switch" as a function, or by defining
    its clauses using anonymous functions, you loose the
    possibility of accessing the local variables of the
    function which uses the "switch".

    As for how I think a real "switch" should be implemented,
    well I think it should behave just like the "switch" of
    well known languages such as C or BASIC does, i.e. it
    shouldn't do anything if no match have been found, unless
    otherwise specified by a "no-match" instruction.

    For example, it might look like this :

    switch theName
    case "Mickey" :
    print "You're a mouse.",cr
    case "Goofy" :
    print "You're a dog.",cr
    oneof "Donald", "Huey", "Dewey", "Louie" :
    print "You're a duck.",cr
    other :
    print "You might be human.",cr
    endSwitch

    I hope this will give you a better idea of what I was
    thinking about.

    Christian

     
  • A.H. Banen

    A.H. Banen - 2002-03-19

    Logged In: YES
    user_id=423153

    Cristian,
    I stand corrected as to the use of anonymous functions
    inside another function. You are right, a switch should be
    context independent.

    Your final example (Pluto might be human :) shows in fact a
    one to one relation with an anlog construction using
    if..elif. Which is clumsy, I agree, but which probably also
    the only construction that could be realised with simple
    rewrite rules:

    TheName = "Pluto"
    # switch theName
    _S_ = theName
    IF FALSE
    #case "Mickey" :
    ELIF _S_ = "Mickey" THEN
    print "You're a mouse.",cr
    #case "Goofy" :
    ELIF _S_ = "Goofy" THEN
    print "You're a dog.",cr
    #oneof "Donald" , "Huey" , "Dewey" ,
    "Louie" :
    ELIF (_S_ = "Donald" )OR(_S_= "Huey" )OR(_S_="Dewey" )OR
    (_S_= "Louie" ) THEN
    print "You're a duck.",cr
    #other :
    ELSE
    print "You might be human.",cr
    # endswitch
    ENDIF

    So when using simple text replacements ( "case" -> "ELIF
    _S_ = ", etc.), a switch would only look less clumsy but
    internally would be just as complicated as the equivalent
    if..elif.

    The better solution, to create an optimized switch which
    would do multiple compares to the same variable (e.g.
    theName) is prferable but will take a good deal of time and
    energy to implement. Which makes it unlikely an
    implementation will take place (on short notice). Which
    shouldn't keep anybody from making requests!

    Andr

     
  • Christian Lesage

    Logged In: YES
    user_id=489834

    Hi Andr,

    I've found that the "match" function of Dialect can be
    turned into something that behaves like a real "switch" :

    testFunc = func()
    y = 10

    s = [["(^1$)|(^2$)", "y = y + 2"],
    [".", "y = 0"]]

    x = 1
    # x is an int and needs to be converted to a string
    interpret(match(unparse(x),s))
    print y,cr

    x = 11
    # x is an int and needs to be converted to a string
    interpret(match(unparse(x),s))
    print y,cr

    endFunc

    testFunc2 = func()

    s = [["^Mickey$",
    "print name + `, you're a mouse.`,cr"],

    ["(^Donald$)|(^Huey$)|(^Dewey$)|(^Louie$)",
    "print name + `, you're a duck.`,cr"],

    ["$Goofy^",
    "print name + `, you're a dog.`,cr"],

    [".",
    "print name + `, you might be human.`,cr"]]

    name = "Huey"
    interpret(match(name,s))
    name = "Pluto"
    interpret(match(name,s))

    endFunc

    testFunc()
    testFunc2()

    While it is a little bit cryptic, this "switch" is more
    powerful than any other "switch" I know of in other
    languages because Dialect's "match" function uses regular
    expressions to make its match and also because it can be
    used more than one time whithout having to make a loop.
    However, it is probably slower than a "if... then...
    elif... then... else... endIf" structure.

    Well, I've just thought that some other people would find
    it useful, so I posted it.

    Bye,

    Christian

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.