Hello together,
i often write switches, where i throw an Exception when something unknown
come in, rather than using a default value.
switch($myVar){
case 1:
doSomethingElse();
break;
case 2:
doSomething();
break;
//...
default:
throw new Exception('Undefined input: ' . $myVar);
break;
}
I would like to write something like this:
switch($myVar){
//...
default:
throw new Exception('Undefined input: ' .
get_the_used_switch_variable());
break;
}
The get_the_used_switch_variable()
is just a placeholder, name can be
changed to something natural...maybe a constant.
It's really usefull, when dealing with nested objects like when you work
with Doctrine.
Best regards
Martin
Hi Martin,
The
get_the_used_switch_variable()
is just a placeholder, name can be
changed to something natural...maybe a constant.
I feel this has diminished utility once you consider that the "switch
variable" is actually an expression and could well include multiple
$variables. Plus there's also the pattern switch(true) { } where the
interesting variables appear in case statements. Hard for me to see
the justification, but maybe I'm missing it. My $0.02...
-- Sandy
The
get_the_used_switch_variable()
is just a placeholder, name can be
changed to something natural...maybe a constant.I feel this has diminished utility once you consider that the "switch
variable" is actually an expression and could well include multiple
$variables. Plus there's also the pattern switch(true) { } where the
interesting variables appear in case statements. Hard for me to see
the justification, but maybe I'm missing it. My $0.02...
Surely that makes it more useful - the switch statement never contains
"multiple variables", it contains a single expression, the exact value
of which is not discoverable to the programmer. A key property of switch
statements is that the expression is evaluated only once, so the engine
is already storing this value, it just needs to be put somewhere accessible.
Perhaps rather than a magic function or constant, though, the switch
statement could be extended with an "as" argument, which would store the
evaluated expression into a normal variable, allowing nesting, and
easier optimisation of the engine where the feature isn't used. Thus you
could write this:
switch( some_expression() as $switch_value ){
case 1:
do_something();
break;
//...
default:
throw new Exception('Undefined input: ' . $switch_value);
break;
}
Which would be shorthand for:
$switch_value = some_expression();
switch( $switch_value ){
...
As it happens, I've been pondering my own proposed extension to
switch(), after some of the discussion that came up from the
standardisation.
Currently, switch always uses a "loose" comparison (==), so cannot
distinguish between "case 3" and "case 3.0". Occasionally, it would be
nice to switch on a strict comparison (===); but then I thought, why
stop there? What if you could use switch with any comparison operator?
My idea is to give the switch() statement an optional "use" clause
(since that's an existing keyword) containing a single comparison
operator, like so:
switch ( $number ) use ( === ) {
case 3:
// ...
break;
case 3.0:
// No longer unreachable! :)
break;
}
But also:
switch ( $age ) use ( < ) {
case 2:
$type = 'infant';
break;
case 18:
$type = 'child';
break;
default:
$type = 'adult';
}
This would work well in combination with the "as" keyword:
switch ( calculate_age($birth_date, $departure_date) as
$age_at_departure ) use ( < ) {
case 2:
$type = 'infant';
$infants++;
break;
case 18:
$type = 'child';
$child_ages[] = $age_at_departure;
break;
default:
$type = 'adult';
$adults++;
}
As well as comparison operators, instanceOf might also be useful:
switch ( $product ) use ( instanceOf ) {
case ProductInterfaces\Flight:
// ...
break;
case ProductInterfaces\Accomm:
// ...
break;
default:
// ...
}
Bitwise operators might be interesting too, but then you're into more
complex implementation, because you've got to evaluate the operator and
cast the result to boolean before evaluating the case. So the
restriction should probably be "any binary operator which evaluates to a
boolean result".
Thoughts?
--
Rowan Collins
[IMSoP]
You can already do:
$a = 1;
$b = 2;
switch( $switch_value = $a + $b ) {
default:
print $switch_value;
}
No magic or new operator required....
-- S.
Perhaps rather than a magic function or constant, though, the switch statement could be extended with an "as" argument, which would store the evaluated expression into a normal variable, allowing nesting, and easier optimisation of the engine where the feature isn't used. Thus you could write this:
switch( some_expression() as $switch_value ){
case 1:
do_something();
break;
//...
default:
throw new Exception('Undefined input: ' . $switch_value);
break;
}
Incredibly, some brave soul has gone back in time and already implemented this, when none of us was looking!
switch($switch_value = some_expression()) {
...
}
--
Andrea Faulds
http://ajf.me/
>
>
>> Perhaps rather than a magic function or constant, though, the switch statement could be extended with an "as" argument, which would store the evaluated expression into a normal variable, allowing nesting, and easier optimisation of the engine where the feature isn't used. Thus you could write this:
>>
>> switch( some_expression() as $switch_value ){
>> case 1:
>> do_something();
>> break;
>> //...
>> default:
>> throw new Exception('Undefined input: ' . $switch_value);
>> break;
>> }
> Incredibly, some brave soul has gone back in time and already implemented this, when none of us was looking!
>
> switch($switch_value = some_expression()) {
> ...
> }
>
Heh, now I feel like a fool for not thinking of that.
Treating assigments as expressions just isn't something that jumps to
mind, I guess!
--
Rowan Collins
[IMSoP]
>
>>
>>
>>> Perhaps rather than a magic function or constant, though, the switch
>>> statement could be extended with an "as" argument, which would store
>>> the evaluated expression into a normal variable, allowing nesting,
>>> and easier optimisation of the engine where the feature isn't used.
>>> Thus you could write this:
>>>
>>> switch( some_expression() as $switch_value ){
>>> case 1:
>>> do_something();
>>> break;
>>> //...
>>> default:
>>> throw new Exception('Undefined input: ' . $switch_value);
>>> break;
>>> }
>> Incredibly, some brave soul has gone back in time and already
>> implemented this, when none of us was looking!
>>
>> switch($switch_value = some_expression()) {
>> ...
>> }
>>
>
> Heh, now I feel like a fool for not thinking of that.
>
> Treating assigments as expressions just isn't something that jumps to
> mind, I guess!
>
Anyone have any thoughts on the use(operator) part, though?
Am I missing something equally obvious there? Or just, it doesn't
interest people much as an idea?
--
Rowan Collins
[IMSoP]
Mit freundlichen Grüßen aus Paderborn
Christian Stoller
Softwareentwicklung
LEONEX Internet GmbH
Technologiepark 20
33100 Paderborn
Tel: 05251-14807-27
Fax: 05251-14807-30
HRB 8694 AG Paderborn
Geschäftsführer: Stephan Winter
------------------------------------------------------------------
APPsolut nützlich - mit Apps neue Geschäftsmodelle & Geschäftsprozesse gestalten
Dienstag, 04. November 2014, mehr unter http://bit.ly/YXDNa3
------------------------------------------------------------------
-----Original Message-----
From: Rowan Collins [mailto:rowan.collins@gmail.com], Sent: Thursday, September 25, 2014 11:10 AM
> Rowan Collins wrote (on 24/09/2014):
>>
>>>
>>>
>>>> Perhaps rather than a magic function or constant, though, the switch
>>>> statement could be extended with an "as" argument, which would store
>>>> the evaluated expression into a normal variable, allowing nesting,
>>>> and easier optimisation of the engine where the feature isn't used.
>>>> Thus you could write this:
>>>>
>>>> switch( some_expression() as $switch_value ){
>>>> case 1:
>>>> do_something();
>>>> break;
>>>> //...
>>>> default:
>>>> throw new Exception('Undefined input: ' . $switch_value);
>>>> break;
>>>> }
>>> Incredibly, some brave soul has gone back in time and already
>>> implemented this, when none of us was looking!
>>>
>>> switch($switch_value = some_expression()) {
>>> ...
>>> }
>>>
>>
>> Heh, now I feel like a fool for not thinking of that.
>>
>> Treating assigments as expressions just isn't something that jumps to
>> mind, I guess!
>>
>
> Anyone have any thoughts on the use(operator) part, though?
>
> Am I missing something equally obvious there? Or just, it doesn't
> interest people much as an idea?
Why should one add a new operator in that context if it is already
possible with assigments as expressions?
This makes the language more complex without getting any improvement.
Christian Stoller wrote (on 25/09/2014):
Am I missing something equally obvious there? Or just, it doesn't
interest people much as an idea?
Why should one add a new operator in that context if it is already
possible with assigments as expressions?This makes the language more complex without getting any improvement.
Sorry, I was talking about this bit:
Currently, switch always uses a "loose" comparison (==), so cannot
distinguish between "case 3" and "case 3.0". Occasionally, it would be
nice to switch on a strict comparison (===); but then I thought, why
stop there? What if you could use switch with any comparison operator?My idea is to give the switch() statement an optional "use" clause
(since that's an existing keyword) containing a single comparison operator
See my earlier e-mail for examples and further details. Maybe I should
have given it its own thread so it was more visible; the idea has been
brewing for a while, I just thought this thread was a convenient place
to mention.
--
Rowan Collins
[IMSoP]
From: Rowan Collins [mailto:rowan.collins@gmail.com], Sent: Thursday, September 25, 2014 12:31 PM
Sorry, I was talking about this bit:
Currently, switch always uses a "loose" comparison (==), so cannot
distinguish between "case 3" and "case 3.0". Occasionally, it would be
nice to switch on a strict comparison (===); but then I thought, why
stop there? What if you could use switch with any comparison operator?My idea is to give the switch() statement an optional "use" clause
(since that's an existing keyword) containing a single comparison operatorSee my earlier e-mail for examples and further details. Maybe I should
have given it its own thread so it was more visible; the idea has been
brewing for a while, I just thought this thread was a convenient place
to mention.
Ah, okay, sorry.
What do you think about that:
$value = 3;
switch (true) {
case 3.0 === $value: break;
case 3 < $value: break;
case 3 > $value: break;
}
Christian
Christian Stoller wrote (on 25/09/2014):
From: Rowan Collins [mailto:rowan.collins@gmail.com], Sent: Thursday, September 25, 2014 12:31 PM
Sorry, I was talking about this bit:
Currently, switch always uses a "loose" comparison (==), so cannot
distinguish between "case 3" and "case 3.0". Occasionally, it would be
nice to switch on a strict comparison (===); but then I thought, why
stop there? What if you could use switch with any comparison operator?My idea is to give the switch() statement an optional "use" clause
(since that's an existing keyword) containing a single comparison operator
See my earlier e-mail for examples and further details. Maybe I should
have given it its own thread so it was more visible; the idea has been
brewing for a while, I just thought this thread was a convenient place
to mention.
Ah, okay, sorry.
What do you think about that:$value = 3;
switch (true) {
case 3.0 === $value: break;
case 3 < $value: break;
case 3 > $value: break;
}Christian
When mixing operators like that, it makes sense to use that style -
although if you're not using fallthrough, there is little advantage over
if/elseif/else:
$value = 3;
if ( 3.0 === $value ) { }
elseif ( case 3 < $value ) { }
elseif ( case 3 > $value ) { }
At the end of the day, all control structures are glorified conditional
jumps, and most switch statements are glorified if/else blocks. To take
one of my examples from last night, you could write:
if ( $product instanceOf ProductInterfaces\Flight ) {
// ...
}
elseif ( $product instanceOf ProductInterfaces\Accomm ) {
// ...
}
else {
// ...
}
Clearly, this works, as would the same thing using switch(true) and case
instead of if/elseif, but the "$product instanceOf" has to be copied
into every clause, and someone reading the code cannot assume that all
the clauses are performing the same test.
In my proposed version, the intent is expressed more clearly, and there
is less risk of a bug being introduced by incorrect copying or refactoring:
switch ( $product ) use ( instanceOf ) {
case ProductInterfaces\Flight:
// ...
break;
case ProductInterfaces\Accomm:
// ...
break;
default:
// ...
}
That's the idea anyway.
Rowan Collins
[IMSoP]
Hi everyone,
switch ( $number ) use ( === ) {
[...]
switch ( $age ) use ( < ) {
[...]
switch ( calculate_age($birth_date, $departure_date) as $age_at_departure ) use ( < ) {
[...]
switch ( $product ) use ( instanceOf ) {
All of these examples are trying to reinvent concepts that can be solved with guards, pattern matching and overloading in other languages. In Erlang one can write the same function name multiple times and guard it ("when" in fact(N)) or match the value ("0" in fact(0)).
fact(N) when N>0 ->
N * fact(N-1);
fact(0) ->
1.
In Scala one could replicate the instanceof behaviour by defining multiple methods of the same name with different argument types.
So I would rather see us making method declarations more flexible to cover those use cases instead of shoving all the functionality into switch/case. Last time I checked the interpreter to try and introduce more features around method declarations, it looks incredibly hard to do in a way that performs well. What is our stance on adding advanced features around declaring methods?
cu,
Lars
Lars Strojny wrote (on 26/09/2014):
Hi everyone,
switch ( $number ) use ( === ) {
[...]
switch ( $age ) use ( < ) {
[...]
switch ( calculate_age($birth_date, $departure_date) as $age_at_departure ) use ( < ) {
[...]
switch ( $product ) use ( instanceOf ) {
All of these examples are trying to reinvent concepts that can be solved with guards, pattern matching and overloading in other languages.
I'm not sure how you see these as equivalent. As I mentioned, a switch
statement is a glorified if/elseif/else, or when fallthrough is used, a
glorified set of if-then-gotos.
fact(N) when N>0 ->
N * fact(N-1);fact(0) ->
1.
Without the additional guarantees provided by a purely functional
environment, that's really just inverting the function header and if
statement.
Adding an extra case to that still means repeating the operator, so
isn't the same as what I was talking about at all:
foo(N) when N>100 ->
N ** foo(N-10);
foo(N) when N>0 ->
N * foo(N-1);
foo(0) ->
1.
In Scala one could replicate the instanceof behaviour by defining multiple methods of the same name with different argument types.
Or, indeed, in most strongly typed languages; in OOP, polymorphism can
be exploited for the same purpose, e.g. using the Visitor Pattern.
Again, I'm not sure what this has to do with switch statements, except
that overloading and polymorphism can both allow you to factor out any
if/switch statement, if you so desire.
--
Rowan Collins
[IMSoP]
Hi Rowan,
[...]
Without the additional guarantees provided by a purely functional environment, that's really just inverting the function header and if statement.
Adding an extra case to that still means repeating the operator, so isn't the same as what I was talking about at all:
foo(N) when N>100 ->
N ** foo(N-10);foo(N) when N>0 ->
N * foo(N-1);foo(0) ->
That is true, for the guarding it is indeed syntactic sugar. Sugar that could probably help with optimisations as it makes reasoning easier from an interpreter perspective but still syntactic sugar.
In Scala one could replicate the instanceof behaviour by defining multiple methods of the same name with different argument types.
Or, indeed, in most strongly typed languages; in OOP, polymorphism can be exploited for the same purpose, e.g. using the Visitor Pattern. Again, I'm not sure what this has to do with switch statements, except that overloading and polymorphism can both allow you to factor out any if/switch statement, if you so desire.
That is exactly my point: instead of "optimising" the switch/case construct which is good enough as if/elseif/else replacement I feel our time would be better spent on thinking of polymorphism, guards and pattern matching.
cu,
Lars
That is exactly my point: instead of "optimising" the switch/case
construct which is good enough as if/elseif/else replacement I feel our
time would be better spent on thinking of polymorphism, guards and
pattern matching.
That sounds a lot like the old "why are you adding features rather than fixing bugs" argument. There are any number of features we could add, but it's not like we have to pick one at a time.