Short-Circuit Evaluation for and?


#1

I was wondering if the and operator uses short-circuit evaluation, I was going to post this but found the answer in the middle of my post. With this REPL test:

!a : ()[println("a") false]
!b : ()[println("should not print") true]
if a() and b()[]

Turns out that and does use short-circuit evaluation. So then why did I crash with a null @pawn_holder below?

if [not @pawn_holder.null? and @pawn_holder.is_locally_controlled?] or @pawn_holder.null?

Because the final evaluation is actually:
not[@pawn_holder.null? and @pawn_holder.is_locally_controlled?] or @pawn_holder.null?

:crying_cat_face:


#2

One of the features that used to be in our old SkookumIDE that we haven’t had a chance to hook back in is a disassembly view. It would show you exactly how Sk parsed some code which is especially useful with operators and trying to figure out the order that things are evaluated.

However there is a little trick you can do to get a disassembly printed to the SkookumIDE Log.

Just wrap the code that you are curious about in a closure and then evaluate it. The result will be the closure which by default prints out a disassembly version of its code.

It must be valid code so I added a clause to the if.

()[
  if [not @pawn_holder.null? and @pawn_holder.is_locally_controlled?]
    or @pawn_holder.null?
    [42]
  ]

When evaluated this prints:

^this: <PawnHolder>
  () <Integer|None>
    [
    if this.@pawn_holder.null?().and(this.@pawn_holder.is_locally_controlled?()).not().or(this.@pawn_holder.null?())
        [
        42
        ]
    ]

And the simplified inside of the closure so you can see that the not took the whole and expression:

if @pawn_holder.null?().and(
  // Evaluated if above true
  @pawn_holder.is_locally_controlled?())
    .not()
      .or(@pawn_holder.null?())

The operators (and other expressions) in SkookumScript uses greedy expression parsing - when looking for an expression it tries to make as big an expression as possible.

Here are two ways you could rewrite it.

With more brackets around the not

if [[not @pawn_holder.null?] and @pawn_holder.is_locally_controlled?]
  or @pawn_holder.null?

Or use the method version of the not operator:

if [@pawn_holder.null?.not and @pawn_holder.is_locally_controlled?]
  or @pawn_holder.null?

I’m sure this is annoying and I can see how it could be confusing though hopefully this helps a bit.

This is a common pattern so I will see if I can come up with a more elegant solution in the future.


#3

Nice trick, that is very handy knowledge for the future. I don’t mind the rewritings, I had thrown more brackets in to fix things initially but the not operator seems a little cleaner.

I tend to get lost in all the brackets <<incoming tangent>> If sticking with a set of 3 colors, the brackets would really pop with a triad color scheme with 120 degrees separation or for 4 colors a tetrad scheme with 90 degrees separation. That is if you want to get all :madsci: with color theory.


Bracket group coloring
#4

A post was split to a new topic: Bracket group coloring


Bracket group coloring
#5

A post was merged into an existing topic: Bracket group coloring


#6

A post was merged into an existing topic: Bracket group coloring