Switch statement

I have a idea.

Right now, I find the current if $choice==0 .... elif $choice==1 .... code block seem to be start slowing down when there’s a lot of blocks. I’m wondering if there can be something like keywords switchif,otherwise,endswitch which does that codeblock. Something that skip the $1==v calculation. Like an advanced arg control block which actually allows you to execute multiple commands at once at a switch case.

For example:


if $1==0 do_something_a
elif $1==1 do_something_b
elif $1==2 do_something_c
...
fi

The above example can be rewritten as

switchif $1 do_something_a
otherwise  do_something_b
otherwise  do_something_c
...
endswitch

If $1 is equal to 5, it will go directly to the fifth otherwise and execute commands within it, and ignores all the calculation for elseif. Or maybe the keyword should just be switch_case,case,done.

That would look like:

switchcase $1
case  do_something_a
case  do_something_b
done

Also, I would like a better way of doing a0.....a1000={expr('x',1000)}, and the numbers don’t have to be numbers. I tried with image, then crop(#-1), but it seems a little slow. expr is single-threaded?

Finally, arg in math parser seem to execute everything inside it, then pick the result. I don’t like that behavior myself, can there be improvement here? The expected result is that it only execute one.

@Reptorian You made so many edits!

Switch would make the code neater. You are missing the case item value that the variable must match and the optional default command when no conditions are met. I suppose a break for each case could be implied.

switch variable
case item command
case item command
default command
done

Bonus for fun, since fi is the counterpart of if, make it hctiws for switch. :rofl:
Edit: Or bign. :copyright::wink:

@David_Tschumperle fi no longer is a shortcut, but in the reference document, fi refers to itself as a shortcut. @grosgood’s tutorial refers to endif, which no longer exists.

On the subject of switch, what if there are two conditions that should be factored into as a single case? I guess a comma as a separator would be possible, but at that point, it’s probably harder to do. So, if variable is equal to 10 and one of the case is aurora,10 then execute case aurora,10 basically.

So you want cases to accommodate conditional statements? That is what ifelifelsefi does.

Yes. Or I want a switch case where no item is needed and implied number. Maybe two different version of switch. One would be switch like you suggested, and the other is switch_number which ignores evaluating conditions and is inherently faster in theory (case without items).

item can be any alphanumeric value in switch statements. At least, that is the expectation of switch from other languages. I understand the desire to truncate it like foreachdone does for repeatlocaldone done.

1 Like

I suppose what is bothering you is having to write and read conditionals: wouldn’t it be nice to simplify by eliminating the repeating $var==?

From:

if $var==1 command
elif $var==2 command
elif $var==3 command
else command
if

To:

switch $var
case 1 command
case 2 command
case 3 command
default command
done

But values not conditionals denote cases.

Note: I don’t know what possessed me to entertain this discussion. I may be wrong about all this because I don’t have much coding experience…

It also would be nice to eliminate the need to do ‘$var’==’$string’ in case of string-based condition.

If you look at pal command, you’d note a lot of +_pal_{short_name_of_pal}, and I’m trying to remove those to a single command. It’s possible, but all solution has some drawbacks while the current version is fast as possible.

If you’re using a lot of if ... elif inside a performance critical section, that’s usually a sign that there’s a more efficient way of doing it (using arrays, maps, different algo entirely).

If you’re going beyond 3 or 4, perhaps consider arg or arg0 - you can assign a variable with a command to execute. Switch statement is a last resort for me in most languages, I only use it if I’m coding quickly/lazily with intent to fix later.

1 Like

I do agree with that, and usually there is a option. However, I point out that I have many subcommands under pal command.That’s a bad thing because more subcommands means G’MIC gets slower from what I have read here, and I wish to have a solution here.

There is no O(1) solution to removing subcommands and keep the time. If/elif/else is O(n), and arg can’t accept multiple command under it. Theoretically, a switch code block for many subcommands instead would solve this. I tested with several Python script to generate G’MIC codes.

You can at the very least create a solution with the same asymptotic performance as g’mic itself, by implementing the same method it uses but in interpreted code. Yes, there’s an overhead.

Another option is to put the definitions of those command inside another (using command). Then you need only “warm it up” when you intend to use them. I also have to wonder - is the perf really that critical? Are you creating new palettes inside a loop or something?

My thoughts on this switch() ... case A : ... case B : ... structure :

  • Personally , I don’t think this is really more readable that using if... elif... else... fi . Particularly if you have a lot of case or if each case is followed by a large code block.

  • In C/C++, I see the advantage of using the switch() syntax: sometimes, the compiler is able to optimize greatly the corresponding code compared to a corresponding use of if... else if... else . I’ve already tried to read the generated ASM code for this kind of switch() construct and I was surprised to see that the compiler had generated an array of pointers to functions, because the number of case was limited, and the range of compared values were like int in [0,10].

  • But for a purely interpreted language, having a switch statement seems useless, as you won’t get compiler tricks as you can get with C/C++.

  • As @garagecoder said, if you want to optimize the expression (as the C/C++ compiler does), then try to explicitly use arrays or named function (with a suffix that is the value of the tested condition).
    Something like:

foo :
  m "case_0 : echo \"0\""
  m "case_1 : echo \"1\""
  m "case_2 : echo \"2\""
  case_$1
  um case0,case1,case2
  • As @Reptorian said, what costs a bit is testing the condition $1==value , for each if. But, this suggests to optimize the evaluation of the condition, rather than introducing a new switch control. I’ll try to see what I can do for quickly testing value1==value2 and value1!=value2, I guess this is something doable (there are already a few simple math expressions that are optimized and that do not require a call to the math parser).

For the foo example, things slow down a lot of you have a lot of m cases as well. It’s quite noticeable too.

Also, could that optimization extend to string than just numbers?

I found that accessing commands does have an annoying delay — how much slower or faster than our other options, I am not certain. For strings, I am in habit of using arg or arg0. I typically have the command do all the decision-making processing before the rest of the code. In my mind, that makes the code more readable and may reduce the structural complexity.

I agree with David that optimizing conditional processing would make things better.

Do you have an example where slow +pal would be a problem? Exactly how fast does it need to be? I have some ideas to try…

I think I’ll wait for the optimization, but right now, +pal is fine in context of speed and I do prefer to remove subcommands to a single command which is where the problems lies in. Unless hopefully, I’m missing something about too much subcommands slowing down G’MIC (I know that would take a lot more). @KaRo did talked about many subcommands before in my G’MIC thread.

All ideas I tried:

  1. Storing pal subcommands into b64 codes - Problem: Loading the image from the base64 code takes up most time. Slower than current code. And using p_subcommand variables with numbers next to it to acts as key for each pals.
  2. m subcommands. - Problem it seems that the importing subcommands slows it down.
  3. Storing pal subcommands into if elif blocks. - Seems fine mostly, however, it’s slower than the current implementation as the farther you stray from 0, the slower it is. If that wasn’t a issue, I’d pick this solution. I have not tried using ‘$var’==’$str’, but used number-based condition instead.

OK, but it would help to have an actual target; just because something is a bit slower doesn’t always mean it’s bad or useless. If you have a specific example where it makes something take several seconds more, then it gives us something to aim for and test against!

Now a separate thread: discuss away!

1 Like

Optimization works in case of number. But from what I see, optimization doesn’t work in case of this:

if '$string'=='$str0'  command_0
elif '$string'=='$str1' command_1
....
elif '$string'=='$str399' command_399
else command_default
fi

I believe it is because it always evaluate ‘$string’. Maybe switch would help in this case because you only need ‘$string’ and the switch control would keep ‘$string’ instead of evaluating it over and over again.

As for @garagecoder: There is no case I found that takes over a second or more. But, the longest case would be using merge command. In the case of pal, here’s the code - G'MIC Pal Command Modified - Pastebin.com .

Using tic toc, pal_new is 10 times slower than current implementation which runs .003 s or less for two palettes. I’d imagine it get really slower if you load many palettes at once. Even base642img has this issue.

1 Like
1 Like