@medvednikov
I started implementing https://github.com/vlang/v/issues/1603 by separating the "match statement" from "switch statement" in parser.v (also to fix https://github.com/vlang/v/issues/1602).
I encountered the problem of parsing:
enum Color{
red, green
}
match 1 {
.red => println(1)
.green => println(2)
else => println(0)
}
We need to specify boundaries of each branch either by "new line" or by any other means. For switch V can just look on the next token to see if it's a "case" and stop statements.
Your made a hack where V checks if the next token is "=>" to stop parsing statements. Also there is an option to implement error recovery to remove my limitations.
I'm ready with "match statement" and "match expression".
Here what I've got.
match 1 {
else => {println(0)}
}
This code is unwrapped to
println(0)
Also you can omit those braces if you are using only one statement there.
match 1 {
else => println(0)
}
Braces allow next case to use enums.
match 1 {
.red => {println(1)}
.green => println(2) // here they could be omitted
else => println(0)
}
a := match 1 {
else => 0
}
unwraps to
a := 0
match 1 {
1 => println(1)
3 => {
println(3)
println(4)
}
else => println(0)
}
This is just like switch works, but you have to use braces for multiple statements for now.
a := match 1 {
1 => 2
3 => {
3
}
else => 5
}
match_expr requires else for now.
match_expr requires the right side of the arrow to be a value. If we allow users to use statements there, then we would have to handle all cases which C doesn't support (i.e. defining variable there).
This is the only difference between match_st and match_expr.
I'll pin a PR as soon as i finish polishing.
Yes, this is a tricky problem.
I wanted to allow multiple statements without braces.
I still think it can be done, but it would be hacky.
I'll think about it and have a look at your PR a bit later.
@medvednikov Lets force braces everywhere for now, so its usable. This means that we can use any value as match condition. And then we will find workout for the problem and remove braces with vfmt (for example).
We suppose that the braces after arrow are required.
Should we create a new scope if we unwrap match statement
This code wouldn't work then:
match 1 {
else => {
a := 1
b := 2
}
}
println(a)
println(b)
match_expr requires the right side of the arrow to be a value
This is good, so long as function calls work too, even if the function returns void like println. (Obviously with void the match statement can't be an expression).
you have to use braces for multiple statements
That's good, braces should always be used to indicate new scopes for consistency. This also simplifies parsing for tools and allows us to avoid possible syntax conflicts.
@Danil-Lapirow That can't work unless each match branch defines the same variables. In that case it would be better to write a, b := match v { and have each branch produce a tuple.
@Danil-Lapirow That can't work unless each match branch defines the same variables. In that case it would be better to write
a, b := match v {and have each branch produce a tuple.
Are you talking about Should we create a new scope if we unwrap match statement?
Yes.
I mean that if in match statement there is else only, we can think of unwrapping it. But should we create a new scope for that code is else branch when we are unwrapping it?
I realized that it would be unclear. So I will remove this.
Why use token => ?
Why not : ?
Example
a := match 1 {
1 : 2
3 : {
3
}
else : 5
}
It's easier/faster to type :)
We don't even need anything after else
a := match 1 {
1 : {2}
3 : {
3
}
else {5}
}
@medvednikov, Any thoughts?
The syntax is already very compact because of no case. => helps to distinct the cases.
=> after else is not needed, good point.
@Danil-Lapirow Yes, after else there is no need to put =>
What if we put or insted of else?
Yes, I know, I like shortening things :)
Example 1
a := match 1 {
1 : {2}
3 : {
3
}
or {5}
}
Or push it even more
Example 2
a := match 1 {
1 : {2}
3 : {
3
}
} or { 5 }
I'm toying around and find out
match 1 {
case 1: print('1')
default: print('def')
}
is perfectly fine in V v.0.1.18
Or push it even more
Example 2a := match 1 {
1 : {2}
3 : {
3
}
} or { 5 }
This one is not good because we can use match in expressions. Like this
a := match 2 {
1 => {2}
2 => {3}
else => {5}
} == 3
V's goal is to be readable, not save keystrokes.
We spend ~80% of our time reading code, and only ~20% writing it. Typing is pretty quick.
@medvednikov You could separate the individual match branches with commas:
match place {
1 => println('I am numero uno!'),
2 => println( 'I got second.'),
3 => println('Third is not so bad.'),
else println('At least I got a plastic participation medal!')
}
The comma does not subtract from the readability, but it does solve the lookahead problem.
@medvednikov You could separate the individual match branches with commas:
match place { 1 => println('I am numero uno!'), 2 => println( 'I got second.'), 3 => println('Third is not so bad.'), else println('At least I got a plastic participation medal!') }The comma does not subtract from the readability, but it does solve the lookahead problem.
From the readability prospective, braces are better because you see actual blocks of code. Though, using them is overhead. IMHO, commas are good, unless, we don't have (or won't implement) anything that uses them.
Perhaps for standalone statements/expressions commas would be required, but they would be optional with braces?
On Aug 26, 2019, at 9:57 AM, Danil-Lapirow notifications@github.com wrote:
@medvednikov https://github.com/medvednikov You could separate the individual match branches with commas:
match place {
1 => println('I am numero uno!'),
2 => println( 'I got second.'),
3 => println('Third is not so bad.'),
else println('At least I got a plastic participation medal!')
}
The comma does not subtract from the readability, but it does solve the lookahead problem.From the readability prospective, braces are better because you see actual blocks of code. Though, using them is overhead. IMHO, commas are good, unless, we don't have (or won't implement) anything that uses them.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/vlang/v/issues/1677?email_source=notifications&email_token=AKKMMKCQJHB2L44J5RFDOZLQGPOLRA5CNFSM4INDPQ4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5EOIPY#issuecomment-524870719, or mute the thread https://github.com/notifications/unsubscribe-auth/AKKMMKFZE4CUC2JFVTOVQRDQGPOLRANCNFSM4INDPQ4A.
Perhaps for standalone statements/expressions commas would be required, but they would be optional with braces?
This is a good option.
match place {
1 => println('I am numero uno!'),
2 => {
println( 'I got second.')
println( 'Somtething')
}
3 => {
println( 'I got second.')
}
else println('At least I got a plastic participation medal!')
}
Thx! Do you think we should have a “=>” after the else for consistency?
On Aug 26, 2019, at 10:03 AM, Danil-Lapirow notifications@github.com wrote:
Perhaps for standalone statements/expressions commas would be required, but they would be optional with braces?
This is a good option.
match place {
1 => println('I am numero uno!'),
2 => {
println( 'I got second.')
println( 'Somtething')
}
3 => {
println( 'I got second.')
}
else println('At least I got a plastic participation medal!')
}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/vlang/v/issues/1677?email_source=notifications&email_token=AKKMMKHV3ZMPDRNAAQVY7X3QGPPC3A5CNFSM4INDPQ4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5EO3BY#issuecomment-524873095, or mute the thread https://github.com/notifications/unsubscribe-auth/AKKMMKEEMA6KBXQQEX36QELQGPPC3ANCNFSM4INDPQ4A.
Good question
Thx! Do you think we should have a “=>” after the else for consistency?
We could also make the else clause of match come after the closing brace:
match place {
1 => println('I am numero uno!'),
2 => {
println( 'I got second.')
println( 'It's good for my self-esteem!')
}
3 => {
println( 'I got third.')
}
} else {
println("At least I got a plastic participation medal!")
}
This will break match expressions.
a := match 2 {
1 => {2}
2 => {3}
else => {5}
} == 3
Or at least wont be as readable.
We could also make the
elseclause of match come after the closing brace:match place { 1 => println('I am numero uno!'), 2 => { println( 'I got second.') println( 'It's good for my self-esteem!') } 3 => { println( 'I got third.') } } else { println("At least I got a plastic participation medal!") }
You're right.
What's wrong with the C syntax, could not it be used instead?
match cond {
1 : print('bad');
2 : print('med')
print('ium');
3 : print('good');
default : print('don\'t know');
}
Relable just fine to me, and shall solve the parsing problems as well (unless it is intention not to use symbols but "new line" as delimiter)
I'm trying to fix the match but there is too much problems like negative numbers, enums, lack of case end, else without arrow.
This syntax is valid and work with all cases.
match 1 {
case -1: {0}
case SOME.ENUM: {1}
default: {-1}
}
To eliminate case I replaced it with ;. I think it could be nice fix but the first case need semicolon before. In last case no semicolon.
match 1 {;
-1 => 0;
SOME.ENUM => 1;
else -1
}
Maybe semicolon is good thing at the end of each case.
Is it good direction?
What do you think?
I tested this approach and it's fits in current implementation with minor changes
match place {
1 => println('I am numero uno!');
2,3 => println('I got second or third.')
println('It\'s good for my self-esteem!');
4 => println('So close.');
else println('At least I got a plastic participation medal!')
}
Or
match place {
1 => println('I am numero uno!');
2,3 => println('I got second.')
println('It\'s good for my self-esteem!');
4 => println('I got third.');
or => println('At least I got a plastic participation medal!')
}
What do you think?
else println('At least I got a plastic participation medal!')Still think it's clearer to use => or whatever symbol (I like the colon somehow) for sonsistency on the default case. otherwise it may look like a lost if-statement
else println('At least I got a plastic participation medal!')Still think it's clearer to use => or whatever symbol (I like the colon somehow) for sonsistency on the default case. otherwise it may look like a lost if-statement
I think you are right the else in match look like lost if-statement or some cpoy&paste error ;)
I think the if-else are connected and work together like switch-case-default and for-break-continue and the like.
I like or (short one), default (long one) or _ (underscore)
Maybe there is a better word instead else?
if-else are connected and work together
Yes. I like underscore because later we might want catch-all matching in other places too, and many languages with pattern matching use it:
match tuple {
7, _ => 'first was 7';
_, x => '2nd matches $x';
_, _ => 'something else';
}
The semicolons help visually separate the previous case's result with the tuple matching expression of the next case. Alex plans to support tuples in V like Go AFAIK.
Multiple statements should require braces in any proposal, because those statements could contain declarations which are only valid for that case. Otherwise the reader could wrongly assume another case was accessing those declarations.
@ntrel good point.
Now I thinking about other approach to match
match place {
1 => println('I'm first!')
println('And I'm know it!')
break
2 => println('Secod place!')
break
_ => println('Maybe 3rd?! Who konws.')
break
}
Let's assume the else thing is figured out and focuse on break. It's nice and clean finishing the case even it is multiline. It visually separate cases from each other. And what's most importatn there is no ; ;)
What do you think?
I agree, else should be replaced with _, as it was originally.
I've considered {} for blocks and no {} for single line matches. But it goes against V's philosophy a bit. {} are required in if and while statements, perhaps we should do the same with match.
I agree,
elseshould be replaced with_, as it was originally.I've considered
{}for blocks and no{}for single line matches. But it goes against V's philosophy a bit.{}are required inifandwhilestatements, perhaps we should do the same withmatch.
But the match has already mandatory {}, the rest shall be separated between => and break
However I would prefer to have a single char equivalent for => like ¬ or # because both = and > are already reserved it could yield errors when a space comes in between = > or the order is wrong <=, =< etc.
both = and > are already reserved it could yield errors when a space comes in between = > or the order is wrong <=, =< etc.
You could make the same argument against << >> += -= etc. The tokenizer takes care of this.
I decided to keep @Danil-Lapirow 's mandatory {}.
It makes the compiler much simpler, it fits with the if/for {} rule, fits the "one way" philosophy, and I think the code is more readable this way.
Thanks @Danil-Lapirow
Even this issue is already closed, please consider if these => are really needed, would it not be sufficient and still clear enough to have just something like this? (taking @Danil-Lapirow 's example)
match place {
1 { println('I am numero uno!') }
2 { println('I got second.')
println('It's good for my self-esteem!') }
3 { println('I got third.') }
} else { println('At least I got a plastic participation medal!') }
By separating else we will force people to use else in the very end.
Although, match expression requires else (maybe until we decide to provide default value for your type) so writing
a := (match place {
1 => { 123 }
2 => { 41 }
3 => { 2 }
} else { println('At least I got a plastic participation medal!') }) == 123
// without parens it's a bit unclear for me.
If we drop => it won't be as readable. The arrow is very notable and clearly separates left and right parts.
Even this issue is already closed, please consider if these => are really needed, would it not be sufficient and still clear enough to have just something like this? (taking @Danil-Lapirow 's example)
match place { 1 { println('I am numero uno!') } 2 { println('I got second.') println('It's good for my self-esteem!') } 3 { println('I got third.') } } else { println('At least I got a plastic participation medal!') }
@Danil-Lapirow I don't think it will be less readable if we drop => as for me it looks more like an operator, only needed to separate both parts in case there were no {} on the right side, even then I would prefer the symbol : for consistency as it is used in other constructs already.
I'm fine with pulling else or _ into the main curved braces as proposed before to safe the parentheses for usage in expressions
IMO, => is cool. Anyway the last word is after @medvednikov. I'll introduce any of these suggestions in a blink of a eye.
IMO,
=>is cool. Anyway the last word is after @medvednikov. I'll introduce any of these suggestions in a blink of a eye.
It might be cool, but is it useful? If you decide to keep it please consider to make it consistent with other similar constructs like the if-statement, e.g.:
if <condition> then {<statements>}
I suppose => means "then"?
if a < b => {
println('$a < $b')
} else if a > b => {
println('$a > $b')
} else => {
println('$a == $b')
}
Look fine for me
IMO,
=>is cool. Anyway the last word is after @medvednikov. I'll introduce any of these suggestions in a blink of a eye.It might be cool, but is it useful? If you decide to keep it please consider to make it consistent with other similar constructs like the if-statement, e.g.:
if <condition> then {<statements>}
I suppose => means "then"?if a < b => { println('$a < $b') } else if a > b => { println('$a > $b') } else => { println('$a == $b') }
@gslicer if you put => everywhere for consistency what about match ?
match place => {
1 => { println('one') }
2 => { println('two') }
3 => { println('three') }
_ => { println('who knows') }
}
It's too many => for me :)
=> will only be used in match expressions.
I think the first => is ablosultely not needed @SewerynKaminski, like below would be clear for me although somehow I'm still not a fan of this operator - especially when it will be used only in the "match" construct and nowhere else ':' is used in V (as in c switch, which I find clear enough)
match place { 1 => { println('one') } 2 => { println('two') } 3 => { println('three') } _ => { println('who knows') } }
And if you tell me, that the following is at least as clear and readable, heck - we can drop "match" entirely:
if place == 1 { println('one') }
else if place == 2 { println('two') }
else if place == 3 { println('three') }
else { println('who knows') }
This would make the language even purer, like the fact that there is no "while", "do... while" but just "for" as a general loop, see:
V has only one looping construct: for.
then if could be stated:
V has only one conditional construct: if.
@gslicer @Danil-Lapirow I've removed => to make it consistent with if {}
match name {
'_win.v', '_windows.v' { '#ifdef _WIN32' }
'_nix.v' { '#ifndef _WIN32' }
'_lin.v', '_linux.v' { '#ifdef __linux__' }
'_mac.v', '_darwin.v' { '#ifdef __APPLE__' }
'_solaris.v' { '#ifdef __sun' }
else { '' }
}
Are => deprecated or removed?
Now match is more V like.
I think we can close this issue.
Most helpful comment
@gslicer @Danil-Lapirow I've removed
=>to make it consistent withif {}