[RFC] Switch Statement

It would require to add a switch keyword. But case and default can be replaced with other available symbols like | and else. It has implicit return.
Other alternatives to else as suggested by @CrazyInfin8 : _, default, otherwise. But it would probably be needed another keyword. If else is not preferred my vote would be for _ (underscore).

// simple
switch (value) {
    | 1 : true,
    | 2 : false,
    | else : Fiber.abort()
}

// multiple instructions per case
switch (value) {
    | "green":
        myfunc.call()
        myfunc2.call()
        return true
    | 2:
        myfunc2.call()
        return myClass.new()
    | else:
        return Fiber.abort()
}

// fall throught
switch (value) {
  | 1 : continue
  | 2 : true // if the value is 1 or 2 would return true
  | 3 : Fiber.abort()
  | else : false
}

Another way without adding a new keyword. if and is

// simple
if (value) is {
    | 1 : true,
    | 2 : false,
    | else : Fiber.abort()
}

// multiple instructions per case
if (value) is {
    | "green":
        myfunc.call()
        myfunc2.call()
        return true
    | 2:
        myfunc2.call()
        return myClass.new()
    | else:
        return Fiber.abort()
}

// fall throught
if (value) is {
  | 1 : continue
  | 2 : true // if the value is 1 or 2 would return true
  | 3 : Fiber.abort()
  | else : false
}

Another syntax variation

// simple
if (value) is {
    | 1 | : true
    | 2 | : false
}

// simple (mutiple cases combined)
if (value) is {
 | [1, 2, 3, 4] | : true // value is 1 or 2 or 3 or 4
 | > 4 | : false
} else {
  Fiber.abort()
}

// multiple instructions per case
if (value) is {
    | "green" | :
        myfunc.call()
        myfunc2.call()
        return true
    | 2 | :
        myfunc2.call()
        return myClass.new()
} else {
   Fiber.abort()
}

// fall throught
if (value) is {
  | 1 | : continue
  | 2 | : true // if the value is 1 or 2 would return true
  | 3 | : Fiber.abort()
} else {
  return false
}

I think we should enforce the block after the ':' for multiline to follow the logic of the rest of the grammar. Single line statement is a bit confusing, but I would expect it to continue by default like would do an if statement and not return of the function, so that part of your implementation is a no go for me.
If possible I would prefer to have something more like this:
switch (value) {
  == 42: {
    System.print("The answer")
    System.print("to the universe")
    continue
  }
  .isEven: {
    System.print("This is odd")
    break
  }
  is String: System.print("How did we get there") // Implicit continue
  else System.print("Karamba")
}

Optionnaly, for ease it would be nice to have a Object::map(fn) { fn.call(this) } so we can write something like:
switch (value) {
  .map {|value| etc... } : etc...
  etc...
}

I like the way that @mhermier has done this which is very natural and flexible. It's also easy to cater for ranges and multiple values:
switch (value) {
   in 1..6: {
      // blah
   }
   in [7, 10, 12]: {
      // blah
   }
}

However, my personal preference would be for the case clauses (whether blocks or single statements) not to fall through at all because, most of the time, this is what you want.
The break and continue statements are best employed  to break out of or continue a loop enclosing the switch statement if there is one.
Instead, I'd introduce a second new keyword fallthrough which would do what it says on the tin. Go uses this word and it's unlikely to have been used much as an ordinary identifier in the past.
Unfortunately, switch probably will have been used a lot and, although I'd prefer to still use it,  a possible alternative here would be when.

Although I really like complicated pattern matching, I don't think it's a good fit for Wren, and even not generally for dynamic languages (although Python will have them in 3.10).
I vote for simple switch, but without fallthrough:
switch (a) {
  case 1: System.print("1")
  case "2":
    System.print("1")
    System.print("A string")
  default: System.print("Nothing of the above")
}

Though I'm not sure this is necessary.

Although a simple switch (without fallthrough) is nice, I'm not sure there's enough value in it to be worth doing.
What I liked about @mhermier's approach is that we can do some simple pattern matching in a natural way.
If we don't bother with fallthrough at all (no great loss IMO), it might even be possible for the compiler to just turn it into an if/else if/else ladder.
Fallthrough isn't often needed in my experience and, if it is, you could do stuff like:
switch (value) {
    in 1..2: {
        if (value == 1) doSomething.call()
        doSomethingMore.call()
    }
    // etc
}

In that case I suggest that the keyword fallthrough is added, and must be
the last expression in the block. Having switch nested in loops is pretty
frequent and reusing continue here would be to much impractical.

Go also insists on fallthrough being the last statement in a case clause. In other words, it can't be conditional which is presumably to make the implementation easier.

Well it can be augmented in a second revision. This is a bare minimum so it
is working.

I personally struggle a little bit with the word fallthrough since it has many double letters and gh position. How about pass?

The problem is that fallthrough is the commonly accepted term for this behavior. pass just doesn't have the same meaning - it's used in Python to mean 'do nothing' - and it's a commonly used identifier in any case.
As well as Go, fallthrough is used by Swift and by C++ 17 (as an attribute). I couldn't find any alternatives at all.
I suppose we could spell it fallthru or use a made-up word such as nextcase but neither look right to me. Perhaps if you think of it as two words, which is really what it is, then  it'll seem more palatable.

I have some ideas I want to share.
switch (expr) {
  |  _: System.print("value is a different number (This is default case)")
  // Alternative default case
  | default: System.print("alternative default case")
  |  1, 2, 3: System.print("value is 1, 2, or 3")
  |  4: System.print("value is 4 but will fall through to next case")
  |> 5: System.print("value may be 4 or 5, because 4 can fall though")
  |  6:
    System.print("this case...")
    System.print("has multiple")
    System.print("instructions!")

}

I think I like @clsource's original syntax where case is replaced with the pipe character.
I think for default case we could use underscore (or if we want to, we could make default a keyword). Also we shouldn't try to constrain the default case to the end especially if we want to add fallthough behavior
I don't think we need the brackets for list of options for a case. instead we can read comma separated items until we hit a colon for multiple values.
I also don't think we need to enclose multiple instructions within blocks. it should probably be enough to do instructions until a line begins with the pipe character (to indicate the next case), or until the closing bracket (the end of the switch)
I think for fallthrough-like behavior, we could add an open angle brace to the next case immediately following the pipe character.

I like the idea of using |> to indicate falltrought.
My preference would be using it at the right position since using if before can be confused with "greater than".
Another option instead of default or underscore (_). Would be using true since it will always be true regardless of the case.
switch (expr) {
  |  1, 2, 3 : System.print("value is 1, 2, or 3")
  |  4      |> System.print("value is 4 but will fall through to next case")
  |  5      : System.print("value may be 4 or 5, because 4 can fall though")
  |  6      :
    System.print("this case...")
    System.print("has multiple")
    System.print("instructions!")
 | true : System.print("This is the default case")
}

What syntax would be used to express the following cases:

expr > 6
expr != 2
expr in 1..50
expr.isEven
expr is String

Regarding the placing of the default case first in the switch, it's something I've never personally liked even though there may be a performance benefit if the default case is much more common than the other cases.
But would it even be possible in a language such as Wren with a single pass compiler?

I think one of the things I hoped switch statements should do was optimize itself for list of numbers so it isn't checking every option like an if-else ladder. because of that, I was also thinking that we should only hold values in cases instead of expressions (similar to how it is done in C).

I'm unfamilliar with the bytecode for now so this is more my concept rather than a what the VM can actually do right now but...

The compiler makes a map for each case value which points to a set of instructions.
If the next case is a fallthrough, then the current case could also make a reference to the next cases and it's instructions (could maybe pose a challange for a single pass compiler but may not be the only way to get the next set of instructions)
If the expression passed to the switch statement matches a case's value, execute the instructions. Or if the expression passed does not match any of the cases but a default case was passed, then run the instructions the default case points to.
if the case selected references any fallthough cases, select that case and execute it's instructions. repeat this step if that case references more fallthough cases.

I guess it may be limiting to not put expressions in a switch statement cases though so maybe we could also have a match statement or switch statement without an expression passed to it. This could behave more like if-else ladders
something like:
// checks for first truthy value
switch {
  |  expr > 5: // do stuff
  |  expre.method: // do other stuff
}
// maybe might reduce ambiguity
match {
  |  expr > 5: // do stuff
  |  expre.method: // do other stuff
}

Also, in my opinion, I disagree with each cases interacting with switch statements. I think operators should still have expressions on both sides, type checks should be as they are, and methods should still contain their receivers even in switch cases.
so none of these would work:
switch (expr) {
  |  >= 5:
  |  .isOdd:
  |  >=7:
  |  is String:
}

Lastly, I don't like this very much either

Another option instead of default or underscore (_). Would be using true since it will always be true regardless of the case.

It may not be often that people are comparing bools in a switch but it still could be possible and this suggestion brings ambiguity,
var aBool = false
switch (aBool) {
  |  true: System.print("aBool is definitely true")
  |  false: System.print("aBool is definitely false")
  |  5: System.print("aBool isn't even a bool")
}

Adding a switch statement was in fact first discussed back in #352 and I think the conclusion then was that it needs to go some way towards pattern matching to be worth doing at all.
Although one can argue about the details, I did feel that @mhermier's variant satisfied that criterion but the other variants discussed did not though I'm grateful to @clsource  for giving the matter another airing.
It seems to me that the other variants can't really handle pattern matching without repeating the control variable in each case which negates one of the benefits of having a switch statement  in the first place. The only benefit it really leaves us with is nicer, more readable syntax and the possibility of fallthrough compared to an if/else ladder.
If some sort of  'jump table' were possible on the lines you suggest, then that would be another reason why a switch statement might be advantageous though I don't know how feasible that would be in Wren.

I don't understand the point of the | as a separator, parsing wise at
best it serve as a separator for blocks but it fells out off place for some
reasons...

I don't understand the point of the | as a separator, parsing wise at
best it serve as a separator for blocks but it fells out off place for some
reasons...

I think the | character as a separator seems similar to saying "or", so something like value1 | value2 is like value1 or value2. The syntax suggested there is the syntax used in Rust.
In my opinion (and this is just an opinion fueled by my bias so it can be disregarded), I don't want wren to resemble Rust as it's sometimes very awkward and Rust traumatizes me ;_;

Also I might add, having the pipe character precede case values may make it easier for the single pass compiler to tell that this is a start of a new case instead of just having variable names, lists, and maps followed by an arrow. Again just guessing as I haven't dug too deep into wren source code.

In all the case _ as default is not an option since it is a valid member
variable name.

In all the case _ as default is not an option since it is a valid member
variable name.

Ah true, I guess if we are putting expressions in the switch statement, might have to use else or default for the default case. In my opinion (gah I'm so opinionionated), I prefer default especially if the default case is not restricted to the last case because putting else sounds like the last case.

Other languages like Elixir have separate simple case conditions from pattern matched ones
https://elixir-lang.org/getting-started/case-cond-and-if.html

case is useful when you need to match against different values. However, in many circumstances, we want to check different conditions and find the first one that does not evaluate to nil or false. In such cases, one may use cond:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...> end
"But this will"

This is equivalent to else if clauses in many imperative languages (although used much less frequently here).

If all of the conditions return nil or false, an error (CondClauseError) is raised. For this reason, it may be necessary to add a final condition, equal to true, which will always match:

iex> cond do
...>   2 + 2 == 5 ->
...>     "This is never true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   true ->
...>     "This is always true (equivalent to else)"
...> end
"This is always true (equivalent to else)"

Finally, note cond considers any value besides nil and false to be true:

iex> cond do
...>   hd([1, 2, 3]) ->
...>     "1 is considered as true"
...> end
"1 is considered as true"

The idea of using the pipe was taken from F#
https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
let printColorName (color:Color) =
    match color with
    | Color.Red -> printfn "Red"
    | Color.Green -> printfn "Green"
    | Color.Blue -> printfn "Blue"
    | _ -> ()

Some ideas. Maybe two separate statements can be is and match.
promoting the existing keyword is to be part of and if.

if is would be similar to C switch matching only bools, strings, nums and lists of possible values. A simpler if table
match would be using pattern matching for each case.

if is (value) { // another possible way would be if (value) is {}
  | 1 : System.print("Case 1")
  | 2 :> System.print("Fallthough") // to case 3
  | 3 : System.print("Case 3.")
  | 4, 5 : System.print("Case 4 or 5")
  | true : System.print("considers any value besides null and false to be true")
} else {
  // The default case
}

match (value) {
  | in 1..6: System.print("Value is in range 1..6")
  | in [7, 10, 12]:> System.print("Value is 7 10 or 12") // fallthough to the next case
  | true: System.print("considers any value besides nil and false to be true")
} else {
  // default
}

Given that we don't want to add more syntax to Wren than we need to, I think that switch (or whatever we decide to call it) needs to be a single statement and it needs to somehow combine traditional usage with simple pattern matching otherwise it's not just not worth doing.
An if/else ladder can after all deal with anything except falling through to the next clause - it's only problem is that it lacks elegance.

OK. following my previous post, I've tried to come up with a design which we might all be able to unite around by going back to traditional switch/case syntax, with no automatic fallthrough, but with default replaced by else to save a keyword. Blocks would not be required for the cases which could be one of the following:

A single value.

A list of values.

A sequence of values.

A type.

A boolean expression.

Option 5 would only be possible if the switch expression were a variable (no problem in practice) which would itself feature in the boolean expression. Other variables which were in scope could also be included.
Fallthrough would be catered for by a new (and spellable) fallthru keyword which would have to be the final statement in a case.
If break and/or continue were present in the code, they would refer to an enclosing loop, not to the switch statement itself.
Here's how it would look:
switch (expr) {
    case 1 :
        System.print("A simple value.")
    case 2, 3, 5 :
        System.print("One of a list of values.")
    case 6..10 :
        System.print("One of a range of values.")
    case is Num :
        System.print("The type of the expression.")
    case expr <= 0 || expr == 4:
        System.print("A boolean expression.")
        fallthru // fall through here
    else :
        System.print("Default case.")
   }

The code would simply iterate through the cases until it found the first match. Cases could therefore overlap each other. It's possible that the compiler might be able to implement this as an if/else ladder though fallthrough might be tricky.

Don't use acronym, autocompletion is a thing since more than 10 years...
Also, I really don't like that each case is specific, it implies special
handling in the compiler for each specific usage, aka code explosion in
the compiler. And last case is not realistic at all. If expr has to be
repeated, it is a simple if.

I assume when you say: "don't use acronym" you mean don't use fallthru - use fallthrough and rely on auto-completion if you have trouble spelling it. I'm not going to argue with that as I don't like the former anyway.
The problem we have with option 5 is that, technically, option 1 is also a boolean expression which evaluates to true unless it happens to be false or null. Unless 'expr' is repeated in option 5 the compiler may therefore have a problem in distinguishing between the two. It also enables the usage of && and || and addresses the dislike some commenters have of cases beginning with an operator.
It  seems  to me that some 'code explosion' is inevitable if traditional and pattern matching approaches are to be combined in a single statement.

My solution is a little bit more elegant, you only have to trick the
compiler to dupe the value on each case, and start evaluating from there.
While it seems to be a lot of case, in fact there is only the general
evaluation of an implicit case value expanded with the explicit expression.
The rest is boiler plate to control the execution flow.
With your solution each case must be parsed and compiled differently. And
this is were you solution ends in code explosion.
I don't say my code is better at all. The importance is also in the ease of
writing, learning and other considerations. But my solution should have
less impact with more extensibility. But this not always the way to go. ex
I really don't like the new tag system, I would have preferred python
decorators, and a proper type annotation, or at minimum that they follow
the wren syntax to avoid the introduction of a DSL...

Misc. thoughts:

Syntax: I prefer keywords to | since Wren mostly uses words rather than symbols outside of expressions.
"fallthrough": the Raku programming language uses "proceed" - https://docs.raku.org/language/control#given

Syntax: I prefer keywords to | since Wren mostly uses words rather than symbols outside of expressions.

Agree

"fallthrough": the Raku programming language uses "proceed"

Nicer alternative

OK. following my previous post, I've tried to come up with a design that we might all be able to unite around by going back to traditional switch/case syntax.

Considering the points made by @cxw42 I think the following syntax can be using only two new keywords: switch and proceed. This syntax was inspired by the @mhermier  syntax.
switch (value) {
    (== 42) { // implicit value
      System.print("The answer")
      System.print("to the universe")
      proceed // fallthrough
    }

    (value.isEven) { // or can be used explicit
      System.print("This is odd")
    }

    (is String) {
     System.print("How did we get there")
    }
 } else {
   System.print("Default case.")
 }

(By the way, thank you all for letting me join you in this discussion!  I enjoy language design :) .)
I agree we are getting closer.
Syntax question

switch (value) {
...
    (value.isEven):  // or can be used explicit

Is value a reserved word here?  It is not currently in Wren, as far as I can tell, but rather a convention.  Would it need to be reserved for something like this to work?---
switch(2+2) {
  (value.isEven) System.print("yes")
}

Syntax comments

I don't think we need the colons if we are using parens --- we should be able to use Wren's regular statement forms.  I like this because it is analogous to if(foo) stmt.  E.g.,
 switch(value) {
   (4) System.print("one-line statement")
   (5) {
     System.print("multi-line block")
    }
  }

I would rather not list the default case as a separate block, for the sake of fallthrough-to-default.  For example, in C, I sometimes write:
 switch(expr) {
   case 1: ...; break;
   case 2:...;
     /* FALL THROUGH */
   default: ...; break;
 }

I think this would be clearer in Wren as
switch(value) {
  (4) {
    System.print("four")
    proceed
  }
  (any) {  // or whatever syntax we pick for the default case
    System.print("default, and also 4")
  }
}

than as
switch(value) {
  (4) {
    System.print("four")
    proceed   // To what?  This makes me look down past two closing braces to find where control will go.
  }
} else {  # Syntax TBD
  System.print("default, and also 4")
}

Semantic+syntactic comment

(== 42) : // implicit value

This looks like it would be tricky to parse.  If nothing else, permitting (==42) might suggest that (42==) would be valid.  I worry we would either break symmetry by forbidding the latter, or greatly complicate the expression parser.
Raku has a nice way to handle this, and I would like to suggest it here for consideration.  This doesn't handle all possible cases yet, but I'd like your feedback if it might make sense for Wren, considered at a high level.

There is an binary operator called "smartmatch", spelled ~~.  It checks whether the left side matches the right side.  E.g., 1 ~~1, and also 1 ~~ 1..10 since 1 is part of the range 1..10.

Every object has a special method that says whether a value matches that object.  In Wren, I would call that method ~~(_), since it is what implements smartmatch.  foo ~~ bar is exactly bar.~~(foo).

In a switch statement, each test expression is a full expression (which the parser can already handle).  The test expression is the right hand side of a smartmatch.  E.g.:
switch(2+2) {
  (4) ...       // Yes, matches: 2+2 ~~ 4 because 2+2 == 4, and Num.~~(_) delegates to ==(_)
  ("four") ...  // No: !(2+2 ~~ "four")
  (Num) ...     // Yes: 2+2 ~~ Num because Num's metaclass has a ~~(_) that matches any number
  (1..10) ...   // Yes: 2+2 ~~ 1..10 because Range.~~(_) matches everything in that range
  (Fn.new { |v| v<=1 || v>=5 }) ... // No: Fn.~~(_) returns the result of passing the argument to the function
}

The parser knows how to handle the expressions, and each expression knows how to check if that case matches.
Two notes:

We could special-case literals like (4) to use == instead of ~~ for speed, if it turned out that was a bottleneck.
We could implement smartmatching behaviour in switch without actually adding the ~~ operator to Wren, if you wanted to consider the operator separately.

Let me know what you think!  If you would like more detail, I would be happy to provide it, or see the linked pages.  E.g., a comparison with JavaScript is here.

I don't understand the point of adding '()' or || around the expression. I mean:
switch(2+2) {
  == 4: ...
  == "four": ...
  is Num: ...
  in 1..10: ... // Maybe it is not a thing, but it also show it is transparent to future binary operators
  ~~ Regexp.new("my fancy regexp") : ...
  ~~ Fn.new { |v| v<=1 || v>=5 }: ...
  ~~ Fn.new { |v| true }: ...
}

Is clear and not ambiguous, and can work even if the author of a library didn't thought at that usage.
Maybe the point is to simulate adding case or allow multiline without adding a block... I don't get it.

An idea, we need to discuss after this issue is resolved that I think comes from python or perl, would be to have the result of the switch to be in a meta variable like _, so it could be used inside the switch block as if a regular switch would be translated as:
{
  var _ = (expr)
  switch (_) {
    is Num: System.print(_) // example of usage
  }
}

If possible I would avoid _ character, since it might be needed to access method objects in the future unless we change the signature system...

A few quick comments:

"fallthrough": the Raku programming language uses "proceed"

Although it's a nice enough word, I have reservations about proceed.
It sounds to me like it's trying to break out of the switch statement altogether and carry on with the rest of the code rather than moving to the next case. Also, from a backwards compatibility viewpoint, it's much more likely to have been used as an ordinary identifier than fallthrough.

I would rather not list the default case as a separate block, for the sake of fallthrough-to-default.

Yes, I think supporting fallthrough rules out the possibility of having a separate else block.

I don't understand the point of adding '()' or || around the expression.

Neither do I.
I've always liked @mhermier's approach here and, unless I'm missing something, I don't think it would necessarily mean that we have to use blocks for multi-line cases which I know some commenters don't like.

There is an binary operator called "smartmatch", spelled ~~. It checks whether the left side matches the right side.

That's a new concept to me - I don't know Raku at all. I'll need to think about it before commenting further.

Well smartmatch is clearly a powerful concept from what is a terse but very expressive language (Raku).
To put something like that into Wren, I think you'd need to:

Add the smartmatch binary operator ~~ (and/or an equivalent match method).

Provide a default implementation in the Object class, perhaps based on object equality.

Override the default implementation in each built-in class (and, where needed, in user-defined classes) as appropriate.

To use it effectively without having to look stuff up all the time, I think you'd need to try and remember how the built-in classes handle pattern matching which might be a high cognitive overhead for a simple language such as Wren.
Although I wouldn't rule this out for the future, I think for now we need to come up with something a bit simpler and more immediately intuitive.
Looking at @mhermier's latest example, I'm quite happy with how he handles the first 4 cases (though I think I might need to open a separate issue about extending the usage of the in operator).
Stuff like this is also easy:
switch(expr) {
    > 6 : ...

    != 7 : ...

    .isEven : ....

    in [1, 3, 5]  : ... // potentially easy anyway

    // etc
}

The key point is that each case always begins with an operator which relates back to the switch expression.
What isn't easy with this syntax are general boolean expressions (involving && and || say) where you really need to pull in the switch variable and possibly other variables for the case to make sense. Unless someone can think of a way to handle these, perhaps it would be best to just be content with simple patterns for now and maybe add more powerful pattern matching later.

About enforcing block, thinking at it again, I think we need to see it in action. I would prefer if we stay on the safe site, so it pairs with if syntax. I guess it is required to avoid a confusion with expression starting with unary left operator, and simplify the compiler.

@PureFox48 I found this default case verbose and error prone, since if the expression evaluate to false it will not be triggered.

Yes, you're right about the default case. I was trying to find a way which begins with an operator to be consistent with the rest of the syntax but it doesn't really work.
What would you suggest - sticking with else: which wouldn't require a new keyword?

I think I agreed with that a while ago. Thought I wonder if user would be confused if default would happens in middle of a selection and catch all prematurely?
This can be solved by moving the else outside of the selection block. While I don't have nothing against it, maybe it is a little bit too much confusing teaching/usage wise, in particular in interaction with if.

Well, as @cxw42  and I said earlier, I don't think we can move else outside of the switch block because of the need to cater for fallthrough.
To avoid potential confusion, perhaps we could mandate that the else case, if there is one, always comes last in the switch.
As far as enforcing blocks is concerned, do we need one if the case ends with a colon?
This, after all, seems to be how C identifies cases without using a block though admittedly it has the case keyword to help it. We'd just have an expression which begins with an operator (or else).

Well I think it is required because potentially, unless I'm mistaken, the grammar would become LL(N). In the context of a multiline , ':' would need to be searched to determine if the expression is a case statement starting with a binary expression or a real statement starting with a unary expression.
'(' will not help obviously.
'|' can be working though distinguishing with bit-wise OR is potentially problematic I guess.

I thought of a simplification late last night.  No smartwatch, but yes parentheses:

(foo) tests for value == foo
{|v|...} for everything else --- calls the function and uses the truth value of its result.

No parser tweaks required because paren vs. lbrace tells you which case you are in, and no run-time overhead.
This doesn't handle literal ranges, which is a downside.  It would be easy to check for ranges at runtime, but at the cost of a type check.  Maybe the compiler could special-case literal ranges, but then the special case would have to handle things like (foo+2*bar)...(bat&3).  I don't know how easy that is in the compiler.

Re. colons, I really think we should not add them if we don't absolutely have to --- @ruby0x1 said at https://github.com/wren-lang/wren/pull/952#issuecomment-815505251 that the syntax for blocks was not open for change right now (if I understood correctly).  Parens and braces do the job using elements Wren already has, even if they look odd compared to other languages :) .

mandate that the else case, if there is one, always comes last in the switch.

Agreed

There is no real confusion here, the grammar interpretation of the block here change because of the keyword switch. So it is safe to use : here, even if it looks a lot like a map.
@cxw42 using '(' since they can start a regular expression does not solve anything. Even considering | or [ or any other operator does not really seems to help. So unless I miss something the solution is either keyword or non ambiguous grammar to preserve LL(1) or LL(2).

I'm in favor of C-style switch with Raku semantics.
That is,
switch (x) {
  case 1..5:
    System.print("x is in the range 1 to 5")
    break
  case "":
  case "s":
    System.print("Something")
    break
  case Num:
  case String:
    System.print("String or Num")
    break
  default:
    System.print("Other")
    break
}

In my experience, fallthrough is almost always not needed. If it is, you can always fall back to if-else. So I tend towards mandating the break, except for adjacent cases. If you think differently, we can allow fallthrough just like C - by omitting the break.
Regarding requiring a default clause, I don't think this is a good idea. Generally I do think we should test for exhaustiveness, but since we don't have pattern matching, I don't think we actually can and requiring default will just create noise.
I can think of two improvements over C's switch:

If the case is one-line, imply the break:

switch (x) {
  case 1..5: System.print("x is in the range 1 to 5")
  case "":
  case "s":
    System.print("Something")
    break
  case Num:
  case String:
    System.print("String or Num")
    break
  default: System.print("Other")
}

Guard clauses:

switch (x) {
  case 1..10 if (x % 2) == 0:
    // ...
    break
}

For the ~~ operator (or whatever it'll be named), we can implement it as the following (preferably in C when possible):
class Class { // Actually, `Class` methods can be implemented only in C, but you got the idea
  ~~(e) { e is this } // By default, classes matches all of their instances, so `case Num` matches all numbers
}

class Bool {
  ~~(e) { e == this }
}
class Num {
  ~~(e) { e == this }
}
class Null {
  ~~(e) { e == null }
}
class String {
  ~~(e) { e == this }
}

class Range {
  ~~(e) { (e is Num && contains(e)) || (e is Range && e == this) }
}

class List {
  ~~(e) { any {|element| element ~~ e } }
}

@mhermier I am trying to understand your points but am having trouble.  Sorry about that!

Colons: I agree there is no ambiguity with maps.
Keyword: Maybe I'm missing something.  The code for ifStatement() https://github.com/wren-lang/wren/blob/main/src/vm/wren_compiler.c#L3119 handles this just fine.

I think the body of a switch can be expr, stmt, expr, stmt... , and Wren's grammar is simple enough that we only need one token of lookahead.
Could you give me a code example or something else to help me understand where we would need extra keywords or lookahead?  If not, I could try writing a proof of concept, but it might take me a while :) .

@cxw42 what I mean:
  switch(val) {
    /* without braces */
    long_check_expression: ... /* actual code follows*/
//  ^                     ^
//  |                     Parsing has to go till there to decide, that long_check_expression is a check expression and
//  |                     not a non brace expression, but it is too late to reinterpret long_check_expression
//  Adding a keyword here can solve the ambiguity, this is what C and most language do

  /* with braces*/
  long_check_expression: ... /* a one liner*/
  long_check_expression: {
   ... /* actual code follows*/
  }
  // There is no ambiguity here since there is no mix between `cases` and regular code
}

I just thought about an extra complication, handling variable declaration in this seems dirty because of fall-through. We might need to ban them.

@ChayimFriedman2 I don't like implicit ~~ as a solution for switch, while perfectly functional, it remove flexibility for the user, and make user depends on the implementor of external code.

Use can always create class Pattern and use full pattern matching. This is just simpler IMO.

Thought about an extra stuff, following while loop, maybe it would be interesting to do something like:
switch (my_long_expression) as myVariable {
  // what ever syntax here we have access to the switch value as myVariable in the block
}
// myVariable is now undefined...

: would need to be searched to determine if the expression is a case statement starting with a binary expression or a real statement starting with a unary expression.

I don't entirely follow that because the case could not begin with a unary expression anyway. The only unary operators we have are: -, ! and ~ and none of those could be used in isolation. A binary operator is needed to refer back to the switch expression.

In my experience, fallthrough is almost always not needed. If it is, you can always fall back to if-else. So I tend towards mandating the break, except for adjacent cases.

I'm struggling to follow your logic re fallthrough here. I agree that it's seldom needed and one of the things I find tedious about programming in C is that you have to remember to put break at the end of each case clause to avoid it from falling through. This in turn means that you can't then use break to exit a loop enclosing a switch.
Surely, it's best for Wren not to allow automatic fallthrough (the 'majority' case) so break can then be freed to fulfil its normal function of exiting loops.

Regarding requiring a default clause, I don't think this is a good idea.

Well, it's been a long thread and I may have missed something but I don't think anyone has suggested that we should require a default clause.  I certainly don't think we should.

I'm struggling to follow your logic re fallthrough here. I agree that it's seldom needed and one of the things I find tedious about programming in C is that you have to remember to put break at the end of each case clause to avoid it from falling through. This in turn means that you can't then use break to exit a loop enclosing a switch.
Surely, it's best for Wren not to allow automatic fallthrough (the 'majority' case) so break can then be freed to fulfil its normal function of exiting loops.

I agree, I just want to keep the break for C familiarity.

Well, it's been a long thread and I may have missed something but I don't think anyone has suggested that we should require a default clause

Oh, you're right. I was confused by:

To avoid potential confusion, perhaps we could mandate that the else case, if there is one, always comes last in the switch.

Skipped "if there is one" 😄.

I don't entirely follow that because the case could not begin with a unary expression anyway. The only unary operators we have are: -, ! and ~ and none of those could be used in isolation. A binary operator is needed to refer back to the switch expression.

You are assuming the future here, we might introduce more operators that might conflict with your statement here. I spoke about the case where the code is something like this:
  switch(expr0) {
    test:
       expr1
       expr2
       expr3
  }

If we don't put brace around expr1/2/3, the whole expressions need to be parsed to see that there is no terminal : to determine if it is an expression (because of unary operators and the continuation of expression with .methodName in next line)

To summary, I only see 2 viable witting style:
switch(expr0) {
  test1: one_liner_expr
  test2: {
    multiline_exprs
  }
  else // `:``is optional here followed by one liner or multiline expressions in a block
}

or
switch(expr0) {
  case test1: oneliner_expr
  case test2:
    multiline_exprs
  default // `:``is optional here, but `else` can't really be used because it could be mixed with multiline expressions
}

case and default can be replaced with anything.
First syntax introduce only 1 symbol while second one requires at worse 3 (not counting required fallthrough or break keyword that is still debated).
Personally I prefer first one, it will introduce less keywords and looks more like the rest of the wren syntax regarding one liners and blocks.

Yes, I think you're right that we're left with basically 2 viable styles.
Like it or not, I suspect the deciding factors here will be:

The need for blocks which I don't think most commenters like given that they're not generally needed in other C-family languages.

Familiar syntax.

As you don't think your own approach can work without blocks for multi-line cases, I'm coming to the conclusion that we need to make the more traditional switch/case syntax work - perhaps on the lines of @ChayimFriedman's latest approach but (please!) with no automatic fallthrough.
We could get by with 2 new keywords (switch and case)  by calling the default case case else:. If we're to allow fallthrough, I personally would prefer that to be the keyword but could live with proceed instead.

Just BTW, VB has Case Else.

Thinking at the switch (my_long_expression) as myVariable for the sake of uniformity maybe it should also be extended to 'if' and also to all loops.

@ChayimFriedman2
I've been studying your latest approach.
Presumably, if guard clauses could be made to work, then we could cater for more general expressions involving 'x' and perhaps other in scope variables as well or am I being over-optimistic.
For (very silly) example:
switch (x) {
    case x > 7:               // open ended range
    case x != 9:              // exclusive value
    case x >= 3 && x <= 10:   // closed range (non-integral)
    case x + y == 6:          // using another variable
    case x.isEven:            // method call
    case Int.isOdd(x)         // method call with 'x' as parameter
    case else:                // default case
}

BTW, in C (and similar languages) complicated conditions can be represented using the following trick:
switch (true) {
    case x > 7:               // open ended range
    case x != 9:              // exclusive value
    case x >= 3 && x <= 10:   // closed range (non-integral)
    case x + y == 6:          // using another variable
    case x.isEven:            // method call
    case Int.isOdd(x)         // method call with 'x' as parameter
    default:                // default case
}

I don't like this trick, but there are others that do.

I don't like, even if polished, it brings no adventages over regular if. Would the following corrected would make sense ?
switch (expr) as x {
    case > 7:               // open ended range
    case != 9:              // exclusive value
    case >= 3 && x <= 10:   // closed range (non-integral)
    case + y == 6:          // using another variable
    case .isEven:           // method call
    case .isOdd:            // method call with 'x' as parameter
    else:                   // default case
}

And then how do you perform a method call with expr as argument (not receiver)?

Using the trick I explained ealier using a method/operator in object, or as @cxw42 named it later '~~'.
switch (expr) as x {
    case ~~ MyUnaryFunction: ...
    case ~~ Fn.new { /* use x directly*/ ...}: ...
    ...
}

It would be better than regular if/else if the complex expressions could co-exist with very simple expressions in the same statement.
Personally, I don't really see how you can have complex expressions without repeating 'x' (or whatever) as it just doesn't look right.

It is interesting in the general case, since usually it is either a value equality check or a property test. For complex expression, I think it start to be interesting when you start to think functional and reusable.
If we go the route you propose, it means that the as become mandatory, meaning we could replace it with something almost equivalent:
with (expr) as x {
    if (x > 7)               // open ended range
    else if (x != 9)              // exclusive value
    else if (x >= 3 && x <= 10)   // closed range (non-integral)
    else if (x + y == 6)          // using another variable
    else if (x.isEven)            // method call
    else if (Int.isOdd(x))         // method call with 'x' as parameter
    else ...                // default case
}

And complete equivalence can be achieved by adding fallthrought to if.

Are you talking there about a possible implementation for switch/case or adding a with statement as well or instead of it?

I mean if we provide full complexity it, it only replace else if with a fancier case...

Well, leaving aside possible compiler optimizations, that's all switch/case really is - syntax sugar for an if/else ladder based on the value of a single expression, albeit more elegant.

Well I see it more like a way to perform a test without the explicit need to named a variable, removing repeat of it XX times. This brings some interest to switch. If the named variable is required all the times, it add no value over the if/else ladder.

Yes, I agree that not having to repeat the switch variable is one of the things that makes it more elegant.
But, I'm not suggesting here that we repeat 'x' all the time - just on those occasions when a complex condition is needed as well as simple ones.

Maybe we can make an hybrid, but it depending if we have block imposed or not, and an extra keyword, by doing something like:
switch(expr) as x {
  case 1:
  case 2:
  other_keyword x + y > 42:
}

But I don't really like it...

You could use case if for complex expressions.
It would be like a guard but without any preceding expression.
switch(expr) as x {
  case 1:
  case 2:
  case if (x + y) > 42:
  case else:
}

While it works, I think it become a burden in case of consecutive matching by other complex mean than equality.
If we had method resolution or something we could provide a secondary argument to change the meaning of case to something like:
switch (expr, .~~(_)) as x {
  case foo: // Would perform: x~~(foo)
  ...
}

I don't think it would become any more of a burden in the case of consecutive matching than an if/else ladder.
There is need for cases to be mutually exclusive and the first case to be satisfied would be the one executed.
If guards were in place, the compiler could replace case if with:
switch(expr) as x {
  case x if (x + y) > 42:
  case else:
}

Re. @mhermier https://github.com/wren-lang/wren/issues/956#issuecomment-817302284:
Thanks for the code example!  I agree the expression and the statement need to be separated by the parser unambiguously.  A keyword can do that, or parens, or any other symbol.  There just needs to be something that's not valid in an expression after the expression, e.g., a colon or a terminal right paren.  I think the keyword at the front is optional, since the parser will know what it's looking for.
Re. @PureFox48 https://github.com/wren-lang/wren/issues/956#issuecomment-817316026:

The need for blocks which I don't think most commenters like given that they're not generally needed in other C-family languages.

I don't want Wren to look like C!  I want it to look like Wren.  I understand not everyone agrees with me :) .  Wren already has well-defined one-liner and block syntax.  I suggest that it's more important to be able to go easily from Wren's if to Wren's switch than from C's switch to Wren's switch.

Well, Wren's if and while statements are exactly the same as in C. Only the for statement differs.
@mhermier and I were discussing earlier what makes switch/case more elegant than an if/else ladder. As well as not usually having to repeat the switch variable, I would humbly suggest that not having to use blocks would be another aspect.

Adding to the list from @mhermier https://github.com/wren-lang/wren/issues/956#issuecomment-817313384 , I propose option 3 (what I said above, but in a compact form):
switch(expr0) {
  (test1) one_liner_expr

  (test2) {
    multiline_exprs
  }

  /* optional feature --- not needed in minimum viable product */
  {|v| v.someFn() } <statement>  // statement can be oneliner or {\n block\n }

  else <statement>
}

Pro: Only one additional keyword (plus whatever we pick for fallthrough), and we can re-use existing parser logic that handles what comes after an if or while keyword for each individual case.
Con: doesn't look like C (but I don't think it needs to)
I support fallthrough being opt-in, not the default.
Minimum viable product?
As you know, I like pattern-matching/smartmatch :) .  Would it be worth discussing those later?  Even if we only had == tests, switch would still make a big difference.  I suggest we narrow the scope of this issue to == until we agree on syntax and semantics for the == case.  What say you?

@PureFox48 Would you please tell me more about the downsides of blocks in your experience?  How do you see those downsides translating to Wren?

I'm talking purely about aesthetics here and trying to add some value to switch/case compared to if/else.
To my mind, blocks make the switch statement look more cluttered and not that much different than an if/else ladder. May be it's just me but that's how I see it.

Fair enough --- thanks for the explanation!

@cxw42 grammatically wise your option is almost equivalent to case 1, with some minor twist to evaluation like the last development. I find it too much confusing because basically it transform "expr expr" as an if statement, which not something we really want in a grammar...
@PureFox48 true, but this is how wren manage multi-line in if in wren...

Perhaps I should make it clear that I've no problem with blocks when they're necessary.
However, if  they're not necessary (and I don't think they are in traditional switch/case syntax) then I'd prefer to dispense with them on aesthetic grounds.

@mhermier

almost equivalent to case 1

Yes, on purpose :) .  Option 3 is just option 1, but with parens instead of case and :.

basically it transform "expr expr" as an if statement, which not something we really want in a grammar...

I'm not sure I understand what you mean here.  Let me try this --- I am thinking of BNF something like:
switch_stmt ::= 'switch' '(' <expr> ')' '{' <cases> '}'
cases  ::= <case>+
<case> ::=   'else' <stmt>
           | '(' <expr> ')' <stmt>

where <stmt> is Wren's regular statement production, and covers both single-line and multi-line.
Anyway, if case <expr>: turns out to be the winner, I'll still use it :) .  I just think it will face an uphill battle, given comments I've seen from the maintainers on other issues.

I'll selectively quote Bob from Crafting Interpreters ---

Do you start from a blank slate and first principles? Or do you weave your language into the rich tapestry of programming history and give your users a leg up by starting from something they already know?
There is no perfect answer here, only trade-offs.

I think, the following would be good for me:
switch (expr[, optionalEqualityCallable]) as x {
  case foo: // Would perform: optionalEqualityCallable.call(x, foo)
  ...
  case if expr:
  case else: // or default which is more natural
}

It should work for most common cases, and let the user customize the notion of equality for case. Like transforming case string literal to do pattern matching, or any other kind of transform required to perform an equality.

The idea of a custom equality checker is an interesting one --- lighter weight than full smartmatch, and more flexible than just ==.
If we are going to use as x, why outside the parens?  That conflicts with our proposal in #964.  And, if you do include optionalEqualityCallable, the x could be very far from where it's used.  What about---
switch([var x = ]<expr>[; optionalEqualityCallable]) {...}

where x's scope is the scope of the switch statement.

@cxw42 I would have loved to be able to do that, but there is a strange feature from if that take precedence, that is bugging me since wren creation.
if (someNewVariableName = 42) { ... }

For me is inconsistent, since it creates a new variable if the variable was not defined earlier. Instead it should be an error in a regular bloc/function, and result in using a setter in a method. This would be more logical.

@mhermier agreed --- the docs say "Wren doesn’t roll with implicit variable definition", so it shouldn't be allowed in an if statement.  Have you opened an issue for that?  I don't se eone.

If there is, it was decided so long ago it was decided/resolved by @munificent himself.

Sorry, if I'm missing something, but this doesn't compile for me:
if (someNewVariableName = 42) System.print(someNewVariable)

I get: Error at 'someNewVariableName': Variable is used but not defined.

@mhermier it looks like that might have been fixed.  I just tried it in wren_cli ---
> if(w=3) System.print("yes")
[repl line 1] Error at 'w': Variable is used but not defined.

Yeah, it looks like all is well after all :)

@ruby0x1 says

I'm letting the thread play out atm. since it's 50+ notifications when I woke up today, for me it's better to just let all the thoughts be explored and when it makes sense to respond, do so holistically

Now I actually am going to log off for now :D

Seems that it not how I remembered. Anyway the as or var is optional to the declaration and can be resolved in another issue.

All of this long discussion make me realize how hard it to bake switch into Wren.
I think we should instead focus on making if-else if-else chains better.
One thing that I always hated is that without braces you cannot really use if-else. The following is invalid in Wren:
if (1 == 0) System.print("Hah??")
else System.print("OK.")

Instead it should be:
if (1 == 0) System.print("Hah??") else System.print("OK.")

Which makes it unusable for if-else if-else chains.
I suggest we change this to allow the else on another line. This is very easy to fix (something I can do in some minutes), yet very useful and much less controversial than switch.

I wish you'd said this 90 odd posts ago :)
Although I'd personally welcome such a change, it wouldn't alter the fact that switch/case can be much more elegant than if/else ladders otherwise languages wouldn't bother with it at all.

While I understand the motivation I'm not sure it helps for readability, But this is another topic for another issue.
And the topic of switch is one of the most interesting exchange for wren I had in a long time. I think it is a good addition, by conformance to other languages and ease of write. Even if there is no concencus/adoption at the end, all that effort is not wasted. It makes people think on language design and make them dig/learn the code.

Below is a side-by-side comparison of a a real-world if/else-if chain and the three options as I currently understand them.  The source files are in the above-linked commit if you want to see where this came from.  The original code is here in wren-toml.  I hope this helps!
// Original - from wren-toml                    // option 1 as I understand it                  // option 2 as I understand it                  // option 3
if (TOMLScanner.isAlphanumeric(char)) {         if (TOMLScanner.isAlphanumeric(char)) {         if (TOMLScanner.isAlphanumeric(char)) {         if (TOMLScanner.isAlphanumeric(char)) {
  scanAlphanumeric()                              scanAlphanumeric()                              scanAlphanumeric()                              scanAlphanumeric()
} else if (TOMLScanner.isWhitespace(char)) {    } else if (TOMLScanner.isWhitespace(char)) {    } else if (TOMLScanner.isWhitespace(char)) {    } else if (TOMLScanner.isWhitespace(char)) {
  // No-op.                                       // No-op.                                       // No-op.                                       // No-op.
} else if (char == "=") {                       } else switch(char) {                           } else switch(char) {                           } else switch(char) {
  addToken(Equal)                                 "=": addToken(Equal)                            case "=": addToken(Equal)                       ("=") addToken(Equal)
} else if (char == "\"") {                        "\"": {                                         case "\"":                                      ("\"") {
  if (peek() == "\"") {                             if (peek() == "\"") {                           if (peek() == "\"") {                           if (peek() == "\"") {
    advance()                                         advance()                                       advance()                                       advance()
    elidedMultiline() // removed for brevity          elidedMultiline()                               elidedMultiline()                               elidedMultiline()
  } else {                                          } else {                                        } else {                                        } else {
    scanString()                                      scanString()                                    scanString()                                    scanString()
  }                                                 }                                               }                                               }
} else if (char == "#") {                         }                                               case "#": scanComment()                         }
  scanComment()                                   "#": scanComment()                              case "[": addToken(LeftBracket)                 ("#") scanComment()
} else if (char == "[") {                         "[": addToken(LeftBracket)                      case "]": addToken(RightBracket)                ("[") addToken(LeftBracket)
  addToken(LeftBracket)                           "]": addToken(RightBracket)                     case "'": scanString("'")                       ("]") addToken(RightBracket)
} else if (char == "]") {                         "'": scanString("'")                            case ",": addToken(Comma)                       ("'") scanString("'")
  addToken(RightBracket)                          ",": addToken(Comma)                            case "{": addToken(LeftBrace)                   (",") addToken(Comma)
} else if (char == "'") {                         "{": addToken(LeftBrace)                        case "}": addToken(RightBrace)                  ("{") addToken(LeftBrace)
  scanString("'")                                 "}": addToken(RightBrace)                       default throwScannerError()                     ("}") addToken(RightBrace)
} else if (char == ",") {                         else throwScannerError()                      }                                                 else throwScannerError()
  addToken(Comma)                               }                                                                                }
} else if (char == "{") {
  addToken(LeftBrace)
} else if (char == "}") {
  addToken(RightBrace)
} else {
  throwScannerError()
}

(note: I picked this code sample by browsing through the ecosystem modules listed in the wiki.  This was the first complex if/else chain I found.)

My personal order of preference is option 3 first (still), then option 1, then option 2.  Any of them is a significant improvement!  I noticed that option 1 is the most concise, which is part of why I prefer it over option 2.

Lastest devellopement the header can be changed to:
if (TOMLScanner.isAlphanumeric(char)) {
    scanAlphanumeric()
} else if (TOMLScanner.isWhitespace(char)) {
    // No-op.
} else switch(char) {
    ...

can be compressed to:
switch(char) {
    case if TOMLScanner.isAlphanumeric(char): scanAlphanumeric()
    case if TOMLScanner.isWhitespace(char): { } // No-op. or break or whatever
    ...

I think it is generalisable with and without case.
And if equality argument is accepted to, with a little bit more of functionnal programing:
var myCustomEquality = Fn.new {|lhs, rhs|
    if (rhs is Fn) return rhs.call(lhs)
    return lhs == rhs
}
switch(char) {
    case TOMLScanner.isAlphanumericFn: scanAlphanumeric()
    case TOMLScanner.isWhitespaceFn: { } // No-op. or break or whatever
    ...

As far as option 2 is concerned, I'm not sure whether we've decided to use case else to save adding the default keyword. Personally, I'm fine with either.

An idea, thought it may bring some confusion, instead of adding a falltrought keyword, maybe continue may be reused here ?

Reading it with some delay, it made me realize that option 1 looks more what shell case does.

I'd prefer not to use continue for fallthrough because we won't then be able to use it to continue a loop enclosing the switch statement.
I suppose we could use a hybrid such as case continue but, personally, I'd prefer to use fallthrough (Go and Swift use it) whose meaning is absolutely clear and is unlikely to have been used much as an identifier in the past.

Any thoughts on my suggestion above that we do == first and then consider expanding the syntax and semantics to other types of comparison?  If we are careful up front, we won't lock ourselves out of other options.  https://github.com/wren-lang/wren/issues/956#issuecomment-817337864

Actually, I've had a further thought about continue.
One thing we haven't talked about so far is whether one should be able to break from the switch statement prematurely before the end of the current case is reached. On the face of it, there seems no reason not to allow this - other languages (including C do) - and the natural keyword to use would be break.
Now, if we did that, then logically continue would be fine for fallthrough.
Moreover, if #964 were to be adopted as well, then we could still break from or continue enclosing loops by the simple device of tagging those loops.
So I think overall that would be a nice solution, which would marry the two proposals and avoid the need for a new fallthrough keyword.
@cxw42
I think we've reached the stage now where we need to hear from @ruby0x1 which, if any, of the options she thinks is worth pursuing before  attempting a preliminary PR or trying to develop that option further.

@PureFox48 I agree this is a good time to pause for review.  Just so I'm not missing anything, are we asking for review of only the three basic syntax options in the side-by-side?  Or also other features?
Sorry I wasn't clear in my last comment --- what I was trying to say is that I think a review of the side-by-side would be good, with other features to be added later.

It might be helpful to extend your table to show how the three options would cater for some basic pattern matching in addition to simple value equality. I think the ability (or at least the potential) to do this is essential for a switch to be worth doing in the first place.
Subject to that, @ruby0x1 should be able to get a feel from the side-to-side which one of the options would fit Wren the best.

@PureFox48 I'll see what I can do - I just worry about combinatorial explosion in the number of options.  Would you be willing to summarize the pattern-matching ideas from the thread?  Then I'll work them into the side-by-side.

Looking for inspiration here is Dart's Switch https://dart.dev/guides/language/language-tour#switch-and-case
Dart Example 1
var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

Dart Example 2
// If you really want fall-through, you can use a continue statement and a label:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

// A case clause can have local variables, which are visible only inside the scope of that clause.

Ideas
So maybe here are some ideas:

change case to for to save a keyword
add parenthesis to use tags for fallthought

var command = 'CLOSED';
switch(command)  as value {

  for ("UNKNOWN"): // empty (no newlines or spaces after : ) is auto fallthought
  for ("CLOSED"):
      executeClosed()
      continue nowClosed // fallthought

  for ("NOW_CLOSED") as nowClosed:
     executeNowClosed()
     // breaks are implicit

  for (value.count > 6): // pattern matching?
     executeBigCommand()

  for else:
   // default case
}

Would you be willing to summarize the pattern-matching ideas from the thread?

Here's a list for Option 2:
switch (x) {
    case 1..5:                   // range of values
    case 6..10 if (x % 2)== 0:   // range with guard
    case 6, 8, 10:               // list of values
    case Num:                    // type of value
    case if x > 12:              // open ended range
    case if x != 11:             // excluded value
    case if x >= 13 && x <= 20:  // closed range (non-integral)
    case if x + y == 16:         // using another variable
    case if x.isEven:            // method call with 'x' as receiver
    case if Int.isOdd(x)         // method call with 'x' as parameter
}

The corresponding ones for Option 1 are:
switch (x) {
    in 1..5:                     // range of values
    in [6, 8, 10]:               // list of values
    is Num:                      // type of value
    > 12:                        // open ended range
    != 11:                       // excluded value
    .isEven:                     // method call
}

Note that I'm using an operator in for a couple of these which doesn't currently exist though I'm thinking of opening a RFC for it.
The ones that are missing compared to Option 2 would probably be handled using ~~ followed by a function. I'd be inclined to exclude those from the comparison for now as they haven't been fully discussed yet.
Perhaps you could fill in Option 3 yourself as I don't think there are any examples in the thread so far.

I think case if <condition> can be replaced with case <variable> if <condition>, for example case x if x > 12 so that you can bind the expression if it is complicated.

I'm not sure what to make of Dart but it looks like a traditional switch with no automatic fallthrough but which nevertheless requires a break statement at the end of each case. You can jump amongst cases using continue followed by a label.
Rather than introduce an Option 4 at this late stage, could we just regard using for rather than case as a sub-option of Option 2.

@ ChayimFriedman2
Yes, I think I said earlier in the thread that's effectively what it would be - the compiler would add the preceding 'x' before the if if you didn't specify it explicitly.

So you always get x?
That's a terrible name.

Well, it would make use of @mhermier's idea of using a tag for a complex expression:
switch (expr) as x {
    case if x > 12:       //  implicit
    case x if x > 12:     //  explicit
}

'x' , of course, could be any valid identifier.

I just didn't see any as in your expression. Either way, I prefer binding in the case clause, but maybe I'm just influenced by Rust, where nested patterns can have bindings 😄

@clsource I'm not a big fan of Dart's switch, myself, but I agree with the point about consecutive labels --- that's something I hadn't thought about.
@ChayimFriedman2 the variable name has to either be a keyword or selected by the programmer in the code, as far as I can tell, because the argument to switch could be a nameless temporary.
@PureFox48 but as x here conflicts with #964.  The same syntax means something completely different.  I'm a believer that similar things should look similar, and different things should look different.  If we really want as x, let's go with switch(expr as x) {...} here and change #964 to LABEL: for(expr) {...} or one of the other options.
all: Just to be clear, the flow-control semantics for this initial check with @ruby0x1 are the same for all the options, right?

Start at the top and execute the first case for which the test passes (whatever the test is)
Only one case runs unless the programmer specifically asks for fallthrough to the next case (whatever the syntax is)

Breaking out of the middle of a case (https://github.com/wren-lang/wren/issues/956#issuecomment-817736135) is TBD

I just didn't see any as in your expression.

That's because there wasn't one. I was just assuming that 'x' was a variable for simplicity :)

Since three of us are on at the moment, would it be worth switching to Discord for a bit of live conversation? :)

There isn't in fact any conflict with #964 because the tag there would be on the loop. Here it's on the switch.

I suspect he meant that we could also want to break out of a nested switch. But that starts becoming more and more goto-y.

But then the programmer has to remember that as x means "value" in one case and "loop" in the other.  It's like all the things that static can mean in C --- they are easy for the experienced programmer, but a real stumbling block for the beginner.

If we are going to name, I would suggest uniformly supporting if(var foo=expr), while(var foo=expr), and switch(var foo=expr)

Then the question is - who is the person we are optimizing programming languages for? I think this is the professional programmer.
But I think we start to discuss not important things. Let's let @ruby0x1 decide what's the direction, then think about it more.

Well, the alternative  would be to use:
var x
switch (x = expr) {
    case if x > 12:       //  implicit
    case x if x > 12:     //  explicit
}

@PureFox48 I much prefer that to overloading as x :+1:

Just to be clear, the flow-control semantics for this initial check with @ruby0x1 are the same for all the options, right?

Yes, I think so.

@ChayimFriedman2

who is the person we are optimizing programming languages for?
As far as I can tell, all of us in this discussion are experienced programmers.  We are certainly part of the target audience :) .

My impression of Wren is beginners are also part of the target audience.  Wren describes itself as a new take on Lua's application space ("Think Smalltalk in a Lua-sized package").  Lua has been successful largely because it is accessible to beginners (4.6M Google hits for "lua programming language for beginners" as I type this).
And, anyway, if it's easier for beginners, it will probably have lower cognitive load for us, too :D .

@PureFox48

switch(x = expr)
I think that would make the parser much easier than the option-1 choices you kindly listed in https://github.com/wren-lang/wren/issues/956#issuecomment-818311465 (thanks for putting that together!).  The parser could, for each case:

Consume an expression
If the expression refers to the variable by name, use it directly
Otherwise, stick <variable> == on the front of the expression, and use that

@cxw42
TBH I hadn't considered nested switch before but if switch is to support break and continue independently in the way I suggested earlier, then you're right that we have to be able to tag switch as well as loops and can't therefore entertain using the tag as a variable alias instead.

My last thought for the day --- I think we should agree on a short-term goal.  @PureFox48 I understand and appreciate that you need what I'll call "complex conditions" (i.e., anything other than equality comparison) in your use cases.  My use cases do not need complex conditionals, though I'll certainly use them once we have them :) .
all: as the working group for switch, I suggest we choose one of the following short-term goals:

Prioritizing a basic switch without complex conditionals; or
Planning a full-featured switch with complex conditionals.

In case (1), basic switch, I think we can meaningfully ask @ruby0x1 to review the side-by-side and give us her thoughts on syntax.  We would then work on complex conditionals once basic switch was implemented.
In case (2), complex conditionals, I think we should spend some more time on the design before we ask @ruby0x1 to review.  Given that we're still coming up with ideas :) , it doesn't seem to me ready for review.
What say you all?

Biggest issue is that if we always think short in grammar, at some point we fill fail hard because of some non anticipated consequences, which will requires crazy expressions, extra keywords or some library to be solved.
The as syntax represent an alias/variable declaration to some value as per import. All the execution flow expressions like while, if, switch... compute a value that is usually thrown away. While I agree the keyword(var x = ...) is nice, the keyword(...) as x can be generalized in all those constructions, and give the benefit of providing a tag for control flow in switch.
The only problem I see with as is that the import grammar precedence seems to implies that the name survives after the expression...
So I think maybe we should sort the assignment first (without ignoring the knowledge we built), which will give the direction to resolve #964 and this one.

@cxw42
Although they haven't been fully explored yet, I think it's clear that all 3 options should be able to deal with complex conditionals to some extent or other.
I'd therefore be on board with asking @ruby0x1 to review these options from the viewpoint of a basic switch to keep things simple for now.

After reviewing the latest batch of points, I think there is a problem with nested switch and the use of continue for fallthrough. This problem stems from the requirement that fallthrough needs to be the final statement in a case clause which Go and (apparently) Swift insist upon. @mhermier, who is probably looking ahead to a possible implementatiion, also said earlier in the thread that he thought this was necessary.
Consider this example (using Option 2 syntax):
switch (x) as outer {
  case 1:
    switch (y) {
      case 1:
         continue outer // error - there's another statement afterwards
      case 2:

      // other cases
    }
    doSomthingElse()  // fly in the ointment
  case 2:

  // other cases
}

Unless, the nested switch happens to be the last statement in an outer switch's case clause, continue outer is going to error out.
I can think of two possible solutions here:

We allow it anyway.

We disallow using continue with a switch tag (but not a loop tag) altogether.

Personally, I'm inclining towards the first of these in the interests of generality.
A minor but awkward point which will need addressing if switch goes ahead.

@PureFox48, I think it is a fair point, and that will need proper testing.

@PureFox48 I think that is a reason to go back to using a different keyword for fall-through.  Also, continue is currently always a backwards jump, and fallthrough is always a forward jump.  I think those are different enough that another keyword wouldn't hurt.

@mhermier

Biggest issue is that if we always think short in grammar, at some point we fill fail hard because of some non anticipated consequences, which will requires crazy expressions, extra keywords or some library to be solved.

I agree this is a risk.  I am also concerned about the risk of doing a full design and then having to start over because we missed something up front.
Do you have specific concerns with the three options in the side-by-side that we could address now, and then still request an early review?  If we could mitigate both risks, that would be great!
(Reminder for those joining the thread:  The three options are, for each case in a switch:

<expr>: <stmt>|<block>
case <expr>: <stmts>
(<expr>) <stmt>|<block>

)

I think that is a reason to go back to using a different keyword for fall-through.

Yeah, you may be right. It's what Go and Swift do even though continue is available to them.

I have decided that I like the requirement for less typing in option 1 :) .  I am willing to support switch using the option-1 syntax.

I am willing to support switch using the option-1 syntax.

...and then there were two (Agatha Christie?).
I started off as an Option 1 supporter before drifting across to Option 2. But I'd be happy with either :)

I vote for option 1. I dont like case keyword xd

I have started a smartmatch-based, option-1 switch implementation at https://github.com/cxw42/wren/tree/switch, just to see how it might go.  It now compiles the following, but executes both cases :) ---
switch(1) {
  1: System.print("one")
  else System.print("nope")
}

May you remove all of the whitespace diffs? It makes it impossible to review.

The Wren codebase is very enjoyable to work with! :D

Indeed 😃

@ChayimFriedman2 now updated and functional!  I haven't undone the whitespace changes yet, but you can diff without them --- https://github.com/wren-lang/wren/compare/main...cxw42:switch?w=1

@cxw42 don't add DUP, revert its removal 001db02c817c201f1fff4b049a0395ad493061c6

@mhermier done, and added some more tests and some complex conditionals.

@cxw42 Some parts are still not elegants/too much noisy:

comment abuse/reuse of a primitive on the alias, not on their declarations.
remove REPORT, makes code noisy and and the user/dev is free to use any mean to trace its code on its own
the noisy comments that explicit the stack content, it should be explicit enough. Just comment about the DUP/POP of topic

@cxw42 rethinking at it maybe we should go something hybrid like this:
switch(a) {
  1: System.print("one")                // literal => a == 1
  "42": System.print("the answer")      // literal => a == "42"
  == 1: System.print("how ? ")          // explicit binaryop equality => a ~~ "abcdefg"
  ~~ "abcdefg": System.print("so nice") // binaryop => a ~~ "abcdefg"
  .isInteger.not: System.print("")      // function call => a.isInteger.not
  else System.print("nope")
}

It would be less surprising for new users, while allow more complex behaviors for cheap.

@mhermier We discussed the hybrid approach above, and it does have some advantages.  How would you distinguish unary + from binary + at the beginning of a case?  E.g.,
switch(a) {
  +1: ... // should match a == +1?  Or should match if (a+1) is truthy?
  +1 != 42: ... // should be interpreted as (a+1) != 42?  How do you know when the parser is at the `+` what to do?
}

@mhermier

Some parts are still not elegants/too much noisy

That's why I haven't opened a PR yet :) .

OK - @PureFox48 take a look at https://github.com/cxw42/wren/blob/switch/test/language/switch/complex-conditional.wren and see what you think about how the complex conditionals look!  I implemented all the ones you listed in https://github.com/wren-lang/wren/issues/956#issuecomment-813660551 .
Wren permits function literals where they are most commonly used: as parameters to method calls.  I realized that, in the current proposal, function literals can also commonly be used as switch tests.  Therefore, the proposal supports:
switch(7) {
  {|v| v>6 }: System.print("yes")     // expect: yes
}

(no Fn.new required)
This means you can't use hash literals as switch tests, but you can get the same functionality from a list of the hash keys.

@cxw42 In fact, there is no ambiguity, there is a bug/feature in the compiler where -42 (and +42 when unary + will be adopted) are not a literal. So:
switch(a) {
  +1: ... // match if `a+1` is truthy
  +1 != 42: ... // match if `a+1 != 42` is truthy
}

@cxw42
Thanks for those examples of complex conditionals which all look good to me :)
I like the idea of dropping Fn.new where the case expressions are functions. As these will always take exactly one parameter (within vertical bars) they can't be confused with map literals where you'd probably want to match on keys (rather than MapEntry's) as being the most useful case.
It's also worth remembering that functions are potentially a very powerful smart-matching weapon as they can capture variables declared outside the switch as well.
Incidentally, for those who don't like the part idea but do like in, this example:
switch("a") {
  "bar".part: System.print("yes")     // expect: yes
}

could be expressed instead as:
switch("a") {
  { |v| v in "bar" }: System.print("yes")     // expect: yes
}

or, if you don't like in either, as:
switch("a") {
  { |v| "bar".contains(v) }: System.print("yes")     // expect: yes
}

I'm afraid that @mhermier's hybrid approach doesn't work at all for me - it's just too much of a muddle.
The beauty of using smart-matching with a switch statement is that every case (except of course else) is treated the same. When the compiler (or human reader) sees this:
switch (e) {
  expr: // do something
}

it's automatically translated to this:
switch (e) {
  e ~~ expr: // do something
}

The isInteger.not example can de dealt with using smart-matching only as follows:
switch(a) {
 { |v| !v.isInteger }: System.print("not an integer")
}

One thing I've been thinking about is how the negative smart-matching operator would fit into all this. I think there are two possibilities to consider:

We don't allow it at all in switch statements (it's still useful for other purposes) on the grounds that negative matches won't be very common.

We do allow it but, if used, it must be the first symbol in the case expression. Moreover, the explicit use of the positive smart-matching operator would be optional as it might be useful for drawing distinctions. For example:

switch(a) {
  ~= 7:  System.print("not equal to seven")
  ~~ 7:  System.print("equals seven")
}

Personally, I slightly favor the second option.
Finally, and without wishing to re-ignite the Option 1 versus Option 2 debate, may I just point out that one can obtain a version of Option 2 (without using if guards) by simply placing the case keyword in front of each case expression (including else) in Option 1. In other words, Option 2 would be just as comfortable using smart-matching throughout.
The reward (if you consider it such) for the extra verbosity would be familiarity with existing switch statements and not having to use a block where the case consisted of multiple statements.

Can we agree on a base benchmark for the feature ?
Because of the syntax decisions, the real questions are:

how frequent a smart-operator adapter will need to be created?
how often a function will need to written and transformed to a closure?

I mean what is the point of using the smart-match switch, if it results in magnitude in worse performance than the if ladder. And to me, as this, that solution simply does not scale at all.

What about this syntax using -> rather than :
var random_var = "c"
// Comma separated
match (random_var) {
  "a" -> System.print("A"),
  "b" -> { // Code blocks allowed
    random_var = "B"
  },
  "c" -> System.print("C"),
  1..3 -> System.print("From 1 to 3"),
  4 | 5 -> System.print("Either 4 or 5"),
  6 if var != "c" -> System.print("6 (and not 'c')"), // Guards (like Rust)
  .isString() -> System.print("%(random_var) is string!"),

  else -> System.print("Fallback case")
}

(pardon the nonsense)

I have no objection to -> vs. :; I prefer colon for reduced typing.  @rice7th your proposal looks similar to https://github.com/wren-lang/wren/issues/956#issuecomment-833423735 .  Why not write the parser and see how it goes?  I think it will turn out to be challenging to parse and special-case everything, but I could certainly be wrong!  I think one of the great benefits of smartmatch-based switch and equality-based switch is that they are very easy to parse.

@cxw42 I prefer -> over : because a) an arrow seems more natural and b) it's easy to lost sight of the : in big match statements


Handle spark's BinaryType

Pull Request Description
Today BinaryType columns get written as a string by just using .toString on a byte array resulting in a value similar to [B@7fdcec67. This PR updates the handling of this column type to write a base64 encoded string instead.

Future Release Comment
[Add description of your change, to include in the next release]
[Delete any or all irrelevant sections, e.g. if your change does not warrant a release comment at all]
Breaking Changes:

None

Features:

None

Fixes:

BinaryType data ingestion

@microsoft-github-policy-service agree company="GitHub"

Hello @fishfood34 , Thanks for the contribution. Looks good to me overall.  Couple of points

This will probably need an update on the docs that binary types by default will get converted to base64.

You will need to bump the maven version for the release too (in the root POM)

@ag-ramachandran I believe I have made the requested changes. Please let me know if you see anything else I missed.


Ux bug, clicking on +New Chat doesn't work when there is no chat history

Hello there 😃
I would like to bring to your attention an ux issue I encountered while registering on your platform. after registration, i clicked on +New chat button in the left and it didn't do anything when there was no recent chats, instead it shouldn't show this button in my opinion
os: windows 11
browser: edge
if you want i can fix it with a small pr

Thanks a lot for your feedback. We will fix it in the near future.

Since the chats dont have any names for now, I don't think it is needed to have multiple empty chats with no identity. So it is better as it is now.

I close this issue because we had a deliberated choice to mantain the current state of the AI Chat. We will be soon changing design of our platform. Stay tuned!


components/openssl: Add support for SNI with SSL_set_tlsext_host_name

I'm not very familiar with this project and its codebase (yet), but I tried sending some API requests with esp-request, which did not work, as the server required SNI, so I added it.

 Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.Andreas Schrägle seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.You have signed the CLA already but the status is still pending? Let us recheck it.

Thanks for sending this, @ajs124 . I'm sincerely sorry noone has gotten back to you earlier.
In a piece of poor coordination, it looks like we've recently implemented this in-house as b65f47c5869. I think the functionality we have now covers the functionality that's in this PR, but you're very welcome to reopen & update the PR if that's not the case.

No problem @projectgus, thanks for responding anyways. As long as this made its way into the codebase somehow, I'm happy.
Although I switched away from the OpenSSL API wrapper, since it does not verify certificates in any way, as far as I can tell and therefore allows for more or less trivial man-in-the-middle attacks.


CLJS and decimals

Hi, thanks for this useful library. However, there is one common problem with JS, precision.
CLJ environment:
(b/+ (b/millimeters 1) (b/meters 1)) => #broch/quantity[1001 "mm"]
(b/* (b/+ (b/millimeters 1) (-> (b/meters 1) (b/millimeters))) (b/meters 1.5)) => #broch/quantity[1501500 "mm²"]
CLJS environment
(b/+ (b/millimeters 1) (b/meters 1))  => #broch/quantity[1000.9999999999999 "mm"]
(b/* (b/+ (b/millimeters 1) (-> (b/meters 1) (b/millimeters))) (b/meters 1.5)) => #broch/quantity[1501499.9999999998 "mm²"]
e.g. https://mathjs.org/ doesn't have this problem.
I don't know what must be done to make this more consistent with JVM results. Maybe somebody thought about this already?

Hi, thanks for bringing this up. I haven't tested this properly in cljs apparently.
I want broch's behaviour in cljs to be equal to that in clj. In clj, I've used ratio's to maintain precision, but this isn't available in cljs (yet). So I will have to solve this differently in cljs, maybe using mathjs as you suggest. However, broch currently has no dependencies, and I would like to keep it that way.
So I'll have a think about how best to solve this. Preferably without introducing dependencies, but I might have to cede that in this case.
I'll keep you posted on this. Again, thanks for bringing it up :smile:

I'm happy to help.
Math.js uses decimal.js and big.js. IIRC these ibraries handle numbers as text.
Some thoughts can be seen in this article based on this article .

Solved in latest release.
Ended up implementing the necessary exact operations on my own ratio type in cljs.
Let me know if there's any further issues.


roles/oraswgi_manage_patches failing due to several variable issues

There are two major issues with oraswgi_manage_patches role probably due to copy/paste errors:

loop_patchid.yml handles osp_loop as list, while in fact it's a dict
loop_stage_patch.yml uses dhc_opatch dict, while probably osp_loop is meant

Fix: https://github.com/oravirt/ansible-oracle/pull/441


Game and some other things are accessible from where they shouldn't

Game should be isolated from drawing functions and from init.lua, along with other selected functions.
It should be functional only in these:

onInit
onUpdate
onTweak
override handlers
observer handlers
binding handlers

Idea from @psiberx :
Add a flag of sorts into mod environment, check the flag in affected functions.
This flag could also be used to sandbox ImGui a bit more clearly.

Made WIP version of something here https://github.com/yamashi/CyberEngineTweaks/commit/5450cbdd4c04c3997496085c7633c4a0aff17575
It could use some more polish, but it seems to do what it was supposed to do.
Leaving this open for now to not forget to clean this up a bit.


Add ignis to tracked elemnts

Summary
Now that there is an ignis package on pypi we can track it in the
meta-repository. Per our standard versioning this bumps the package
version to 0.8.0.
Details and comments

can we also do the patch to terra

There isn't a terra release with the backported patch yet. Once there is I can do a follow up patch to bump the terra requirement here too. We can hold off on actually pushing the 0.8.0 release here until we have terra 0.7.1.


Feat/get task using skill level

what is the change?

Added an API that will return a task based on the skill and level provided.
closes #701

need to write tests so changing the PR to draft

closing this PR as we do not need this API, a middleware will be made which will assign the task automatically


Backport Spring and jackson-databind version bump to 2.x (#759)

Backport Spring and jackson version bump

Check List

[ ] New functionality includes testing.

[ ] All tests pass, including unit test, integration test and doctest

[ ] New functionality has been documented.

[ ] New functionality has javadoc added
[ ] New functionality has user manual doc added

[x] Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Codecov Report

Merging #775 (4417b86) into 2.1 (fc476e5) will increase coverage by 3.03%.
The diff coverage is n/a.

@@             Coverage Diff              @@
##                2.1     #775      +/-   ##
============================================
+ Coverage     94.67%   97.71%   +3.03%
  Complexity     2801     2801
============================================
  Files           280      270      -10
  Lines          7570     6912     -658
  Branches        558      439     -119
============================================
- Hits           7167     6754     -413
+ Misses          349      157     -192
+ Partials         54        1      -53

Flag
Coverage Δ

query-workbench
?

sql-engine
97.71% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files
Coverage Δ

workbench/public/components/SQLPage/SQLPage.tsx

workbench/public/utils/PanelWrapper.tsx

...ublic/components/QueryResults/QueryResultsBody.tsx

...h/public/components/QueryLanguageSwitch/Switch.tsx

workbench/public/application.tsx

workbench/public/components/PPLPage/PPLPage.tsx

workbench/public/components/Main/main.tsx

workbench/public/components/app.tsx

...ch/public/components/QueryResults/QueryResults.tsx

workbench/public/components/Header/Header.tsx

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.


refine common black sprite, the legs are looking weird when over other colors

The head also looks weird when looking left or right

or we could put an entire black square behind it


Update sbt-github-actions to 0.9.5

Updates com.codecommit:sbt-github-actions from 0.9.4 to 0.9.5.
GitHub Release Notes - Version Diff
I'll automatically update this PR to resolve conflicts as long as you don't change it yourself.
If you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.
Configure Scala Steward for your repository with a .scala-steward.conf file.
Have a fantastic day writing Scala!

Ignore future updates
Add this to your .scala-steward.conf file to ignore future updates of this dependency:
updates.ignore = [ { groupId = "com.codecommit", artifactId = "sbt-github-actions" } ]

labels: sbt-plugin-update, semver-patch

Superseded by #46


ttwatch --set-name succeeds but return error "Unable to write new watch name"

When updating the name of my watch, it reports that it fails, even though it doesn't:
$ /usr/local/bin/ttwatch --devices
**SOME_ID**: TomTom GPS Watch
$ /usr/local/bin/ttwatch --set-name "Grimlers tomtom"
Unable to write new watch name
$ /usr/local/bin/ttwatch --devices
**SOME_ID**:  Grimlers tomtom

Same phenomena with and without root. --set-time works fine. I did some digging and this is where the error comes from:
if (ttwatch_update_preferences_modified_time(watch) != TTWATCH_NoError)
    write_log(1, "Unable to write new watch name\n");

at line 246 in ttwatch.c.
The error code is 16, i.e. TTWATCH_InvalidParameter which should mean that error comes from line 992 in libttwatch.cpp:
if (!watch)
    return TTWATCH_InvalidParameter;

I see that DAYNAMES and MONTHNAMES are defined as Sun, Mon, ... and Jan, Feb, ... in ttwatch_update_preferences_modified_time. The language of my TomTom Runner 2 Cardio+Music watch is set to Swedish which means that the day names and month names are different (I think), could this be the cause of the problem?
Please let me know if I can provide any more information!

Problem has disappeared today (after rebooting computer). I'll reopen if it appears again.

Interesting. Glad it's working now though. FYI, I don't think the language could have been the issue anyway, since those names are used only for updating the internal last-modified timestamp in the preferences XML file, which is always is English anyway.

@ryanbinns Thanks for the information, good to know!


Document - What is ExpressRoute Local?

The document states that _*This limitation does not exist for ExpressRoute Local in Virtual WAN. What does this mean? What limitation does not exist exactly?
If I had two Express Route Local Circuits. The provider is Equinix in London, one circuit in UK South and one in UK West, and I peered the UK South Circuit with the virtual hub in UK South and UK West circuit with a virtual hub in UK West (Both in the same Azure VWAN resource) Is that a supported scenario?
The London POP Azure Local Region for Express Route Local is only UK South. In my scenario, it fails the connection and asks me to upgrade to standard.

Document Details
⚠ Do not edit this section. It is required for learn.microsoft.com ➟ GitHub issue linking.

ID: 3cdb32c0-628d-0be2-f514-477d46dfa1b8
Version Independent ID: fa096059-2d16-30a2-1e8b-8b9671afcaa4
Content: FAQ - Azure ExpressRoute
Content Source: articles/expressroute/expressroute-faqs.md
Service: expressroute
GitHub Login: @duongau
Microsoft Alias: duau

@georgeollis , thank you for your query. We've assigned this issue to the doc author for review & clarification.
@duongau , could you please add some clarification around the note?

Hello @georgeollis, the note has a * at the front which refers to the second sentence in the first paragraph. Therefore, the limitation of ExpressRoute local only being able to access regions in the same metro doesn't apply in a Virtual WAN configuration. I'll submit a change to the documentation so that is clearer. Thank you for helping us improve the documentation. #please-close

How about a UK West Express Local in London? The provider would be Equinix. Because that provider doesn't support UK West in ER local, they would need to ER Standard. Is that correct?


cannot find some idea dependencies we used in maven central anymore...

see https://youtrack.jetbrains.com/issue/JBR-3089

@XenoAmess
Their EAP seems to broke dependencies. I've observed a bit different error to yours, but after my fix, CI/CD is able to build a plugin
My solution is in these commits:
https://github.com/valb3r/flowable-bpmn-intellij-plugin/commit/e78b7b39ae8a90361138c39ad862fe6cca021dc7
https://github.com/valb3r/flowable-bpmn-intellij-plugin/commit/79106b50c3a3f2ec2bf2b20a2f37da71d5bd7acb
https://github.com/valb3r/flowable-bpmn-intellij-plugin/commit/349d649cbcd2ffdf9f599c53b8b18894adef5f3c
Or you can clone the feature/FBP-206-add-scroll-bar-support branch and apply changes only from gradle files:
https://github.com/valb3r/flowable-bpmn-intellij-plugin/compare/feature/FBP-206-add-scroll-bar-support
That branch builds perfectly in CI/CD
https://github.com/valb3r/flowable-bpmn-intellij-plugin/runs/1869349045
I think this is something related to:
https://github.com/JetBrains/gradle-intellij-plugin/issues/369

please tel me and close this issue when solved in branch master

@XenoAmess fixed in master

@valb3r I saw it. Thanks!


Fix UI flashing

When submitting a request the UI input was being set to disabled. Unfortunately this caused the UI to "glitch" since the input field and selector dropdown icon backgroudns were white.
By inheriting the background-color from the parent elements the UI stays the same when disabled and one no longer has the feeling that the app is broken.
Without the changes:

With the changes:

the fields are still disabled and if the user goes with the mouse over them he would receive the normal feedback that he cannot do anything in the field.

Thanks @compojoom, that bug was annoying. :-)

Sorry, I ignored this glitch so far, because I knew we will throw away this part of the code anyway. But now as we have the fix, I don't see a reason not to just merge it. We need to ensure that #817 is not breaking it again.

Is there a reason why we're not merging this?

I usually don't merge PRs if I'm not the author. :shrug:

@compojoom ?

So, if you receive a PR from the public - you would expect the public to merge?

So, if it is approved - someone from the team needs to merge it.

So, if you receive a PR from the public - you would expect the public to merge?

I haven't perceived you as an external from the public. 🙂
I would also expect the author to interact with the team if he wonders why his PR doesn't get merged. 🤷🏾


GitHub theming / dark mode

GitHub offers a nice dark mode. It would feel only consistent to play along and add a dark mode to StarHub, too. I think the best would be to use the API of GitHub to gather the setting from GitHub itself:

If this isn't possible, providing the same settings would be great, nonetheless.

Feel free to modify the CSS and submit a PR @martin-braun, we can include it when time allows it.


reactive extension library issue?

VSCode Version: Code 1.14.1 (2648980a697a4c8fb5777dcfb2ab110cec8a2f58, 2017-07-13T19:08:57.197Z)
OS Version: Darwin x64 16.6.0
Extensions:

Extension
Author (truncated)
Version

html-snippets
abu
0.1.0

mustache
daw
1.0.0

coldfusion
ili
0.0.10

automagic-code
jai
0.0.2

sde
jin
2.0.20170209

Angular2
joh
2.4.0

vscode-JS-CSS-HTML-formatter
lon
0.2.3

Go
luk
0.6.62

code-beautifier
mic
1.7.2

debugger-for-chrome
msj
3.1.6

cordova-tools
vsm
1.2.7

vscode-react-native
vsm
0.3.2

twig
wha
1.0.2

Steps to Reproduce:

Reproduces without extensions: Yes/No

Please file this agains the react native extension


Fix typo in documentation

There's a typo in the documentation regarding the serviceWorkerFilename that's fixed by this PR :)

That's an important typo. Thanks @AndreJoaquim  for contributing the fix!