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