Re: [boost] [Boost][Proposal] library for enhanced switch syntax.
Phil Endecott wrote:
Specifically thinking about strings, there are numerous ways that it could be done. Starting with (1): the obvious sequence of if-else-if: ... (2): binary search using nested switches: ... (3) character-by-character comparison using nested switches: ... (4) converting to a 64-bit integer, for strings of up to 8 characters: ...
Firstly my implementation was never particularly about string in "switch" it is just one of the applications. Secondly, example 3-4 assume additional implementation( can take quite a time to do it right ), it isn't like you have it out of the box, this is exactly what my statement was about( example 1-2 don't count, they are non-scalable ). Lets rather consider something that is more complex: -- Example_1 "Parse file by extension": switch( hash_it( get_file_extention( file_name ) ) ) { case "cpp"HASH: case "cc"HASH: case "c++"HASH: case "cxx"HASH: case "C"HASH: { ... } break; case "hpp"HASH: case "hh"HASH: case "h++"HASH: case "hxx"HASH: case "H"HASH: { ... } break; } // OR // I think this way it is much readable eswitch( get_file_extention( file_name ) ) >> case_( any_from( "cpp", "cc", "c++", "cxx", "C" ) ) >> [&]{...} >> case_( any_from( "h", "hpp", "hh", "h++", "hxx", "H" ) ) >> [&]{...}; // OR // even this could be possible( but not yet implemented ) eswitch( get_file_extention( file_name ) ) >> case_( "cpp", "cc", "c++", "cxx", "C" ) >> [&]{...} >> case_( "h", "hpp", "hh", "h++", "hxx", "H" ) >> [&]{...}; -- Example_2 "Parse HTTP header with Regex": // O_o too much boilerplate if( std::regex_match( line, "^.+ 200 .+$"_r ) ){...} else if( std::regex_match( line, "^.+ 404 .+$"_r ) ){...} else if( std::regex_match( line, "^.+: .+$"_r ) ){...} else { terminate(); } // OR // I think this way your intention is clearer eswitch( line ) >> case_( "^.+ 200 .+$"_r ) >> []{...} // match for "HTTP/1.1 200 OK" case_( "^.+ 404 .+$"_r ) >> []{...} // match for "HTTP/1.1 404 Not Found" case_( "^.+: .+$"_r ) >> [&]{...} >> // match for "key: value" default_ >> []{ terminate(); }; -- Example_2 "match in range of values": // Error prone approach if( value >= 1 && value <= 10 ){ Print("Value in a range[1,10]"); } if( value >= 11 && value <= 20 ){ Print("Value in a range[11,20]"); } else { Print('?'); }; /// OR eswitch( value ) >> case_( _1.in( 1, 10 ) ) >> []{ Print("Value in a range[1,10]"); }
case_( _1.in( 11, 20 ) ) >> []{ Print("Value in a range[11,20]"); }
default_ >> []{ Print('?'); }; // _1 it is lazy index mapping for the params in eswitch
I my opinion "eswitch" looks more readable, more intuitive, less error prone and furthermore it is extensible. P.S. Here https://github.com/rabdumalikov/proposals/blob/master/eswitch_boost_proposal... I had described why I think it is important( just in case you've missed it ).
On 11. Nov 2019, at 18:39, рустам абдумаликов via Boost
wrote: // I think this way it is much readable eswitch( get_file_extention( file_name ) ) >> case_( any_from( "cpp", "cc", "c++", "cxx", "C" ) ) >> [&]{...} >> case_( any_from( "h", "hpp", "hh", "h++", "hxx", "H" ) ) >> [&]{...};
// OR // even this could be possible( but not yet implemented ) eswitch( get_file_extention( file_name ) ) >> case_( "cpp", "cc", "c++", "cxx", "C" ) >> [&]{...} >> case_( "h", "hpp", "hh", "h++", "hxx", "H" ) >> [&]{...};
-- Example_2 "Parse HTTP header with Regex":
// O_o too much boilerplate if( std::regex_match( line, "^.+ 200 .+$"_r ) ){...} else if( std::regex_match( line, "^.+ 404 .+$"_r ) ){...} else if( std::regex_match( line, "^.+: .+$"_r ) ){...} else { terminate(); }
// OR
// I think this way your intention is clearer eswitch( line ) >> case_( "^.+ 200 .+$"_r ) >> []{...} // match for "HTTP/1.1 200 OK" case_( "^.+ 404 .+$"_r ) >> []{...} // match for "HTTP/1.1 404 Not Found" case_( "^.+: .+$"_r ) >> [&]{...} >> // match for "key: value" default_ >> []{ terminate(); };
-- Example_2 "match in range of values":
// Error prone approach if( value >= 1 && value <= 10 ){ Print("Value in a range[1,10]"); } if( value >= 11 && value <= 20 ){ Print("Value in a range[11,20]"); } else { Print('?'); };
/// OR
eswitch( value ) >> case_( _1.in( 1, 10 ) ) >> []{ Print("Value in a range[1,10]"); }
case_( _1.in( 11, 20 ) ) >> []{ Print("Value in a range[11,20]"); }
default_ >> []{ Print('?'); }; // _1 it is lazy index mapping for the params in eswitch
I my opinion "eswitch" looks more readable, more intuitive, less error prone and furthermore it is extensible.
I don't like this syntax, it is awkward and making the code less readable. 1) You are replacing a normal switch, which may be limited in its abilities but is well known even to beginners with something that has a rather unintuitive syntax. The shift operators are associated to streaming in C++ these days, but you use them differently here. Someone who reads this code who is not familiar with eswitch will not immediately understand this. Why did you chose operator>> instead of operator<< ? I think the choice is arbitrary and therefore hard to remember. 2) Your syntax requires one to type a lot of characters. I don't think one should replace the switch but if one did, the following syntax would be more economic and easier to remember, because it is less arbitrary eswitch( value, case(match1), lambda1, case(match2), lambda2 , … , default(), lambdaN ); Best regards, Hans
I don't like this syntax, it is awkward and making the code less readable.
1) You are replacing a normal switch, which may be limited in its abilities but is well known even to beginners with something that has a rather unintuitive syntax. The shift operators are associated to streaming in C++ these days, but you use them differently here. Someone who reads this code who is not familiar with eswitch will not immediately understand this. Why did you chose operator>> instead of operator<< ? I think the choice is arbitrary and therefore hard to remember.
2) Your syntax requires one to type a lot of characters. I don't think one should replace the switch but if one did, the following syntax would be more economic and easier to remember, because it is less arbitrary
eswitch( value, case(match1), lambda1, case(match2), lambda2 , … , default(), lambdaN );
PS: I forgot to replace `case` by `case_` and `default` by `default_` but you get the idea.
On 2019-11-12 13:32, Hans Dembinski via Boost wrote:
I don't like this syntax, it is awkward and making the code less readable.
1) You are replacing a normal switch, which may be limited in its abilities but is well known even to beginners with something that has a rather unintuitive syntax. The shift operators are associated to streaming in C++ these days, but you use them differently here. Someone who reads this code who is not familiar with eswitch will not immediately understand this. Why did you chose operator>> instead of operator<< ? I think the choice is arbitrary and therefore hard to remember.
2) Your syntax requires one to type a lot of characters. I don't think one should replace the switch but if one did, the following syntax would be more economic and easier to remember, because it is less arbitrary
eswitch( value, case(match1), lambda1, case(match2), lambda2 , … , default(), lambdaN );
PS: I forgot to replace `case` by `case_` and `default` by `default_` but you get the idea.
On the topic of better syntax, there are a few examples in Boost: https://www.boost.org/doc/libs/1_71_0/libs/phoenix/doc/html/phoenix/modules/... https://www.boost.org/doc/libs/1_71_0/doc/html/lambda/le_in_details.html#lam... Though, I'm not convinced about the usefulness of the proposed eswitch library.
Why did you chose operator>> instead of operator<< ? Because my intention was to show "control flow transition" which goes in my case from left to right, thus ">>" and not the other way around "<<".
// I think the choice is arbitrary and therefore hard to remember. Nope, it was intentionally. Also I had on my mind following syntax with
I don't think one should replace the switch... This sentence confuses me. What do you mean? You're either saying that we shouldn't try to extend "switch" anyhow or you meant something else. In case of( "switch shouldn't be extended..." ), then please explain your
eswitch( line ) >> // pass control to following "case_"
case_( ... ) >> // pass control to lambda and execute if case_ was matched
[]{...} >> // pass control to "falling_option"
fallthrough_ >> ...;
pipes "|":
eswitch( line ) |
case_( "^.+ 200 .+$"_r, []{...} ) |
case_( "^.+: .+$"_r, []{...} ) |
default_( []{...} );
position in more details? Otherwise it sounds like: "I just don't like it".
What I see everywhere, people actually extend "switch", for instance:
"Swift", "C#", "Java", "JavaScript", "LLVM StringSwitch" and I think there
is even more.
I think there is a reason for that, because "switch" is much convenient and
more readable then "if-elseif-else" in some cases.
By the way syntax isn't a problem, I can change it.
Regards
RAbdumalikov
вт, 12 нояб. 2019 г. в 12:32, Hans Dembinski
I don't like this syntax, it is awkward and making the code less readable.
1) You are replacing a normal switch, which may be limited in its abilities but is well known even to beginners with something that has a rather unintuitive syntax. The shift operators are associated to streaming in C++ these days, but you use them differently here. Someone who reads this code who is not familiar with eswitch will not immediately understand this. Why did you chose operator>> instead of operator<< ? I think the choice is arbitrary and therefore hard to remember.
2) Your syntax requires one to type a lot of characters. I don't think one should replace the switch but if one did, the following syntax would be more economic and easier to remember, because it is less arbitrary
eswitch( value, case(match1), lambda1, case(match2), lambda2 , … , default(), lambdaN );
PS: I forgot to replace `case` by `case_` and `default` by `default_` but you get the idea.
participants (3)
-
Andrey Semashev
-
Hans Dembinski
-
рустам абдумаликов