Shop OBEX P1 Docs P2 Docs Learn Events
New CAST instruction for Spin2 — Parallax Forums

New CAST instruction for Spin2

It's been bugging me for a long time that there's no way in Spin to do a deterministic one-of-n branch.

The CASE instruction serially tests cases and then jumps to a code block when a match is found, but that's slow for many cases.

When you know you want to run a particular block of code based on an index value, it would be nice to have something akin to a jump table, but in a structured format.

I made a new instruction called CAST, which is kind of like CASE, but takes an index value and uses it to look up an offset word to select the routine to run. This means only one decision has to be made, instead of a bunch of serial decisions.

What syntax looks best?
  cast x
    : block_0
    : block_1
    : block_2
    : block_3
    : block_4
    : block_5
    : block_6
    > block_other

  cast x
    0: block_0
    1: block_1
    2: block_2
    3: block_3
    4: block_4
    5: block_5
    6: block_6
    >: block_other

  cast x
      : block_0
      : block_1
    2 : block_2
      : block_3
    4 : block_4
      : block_5
    6 : block_6
    > : block_other

  cast x
      : block_0
      : block_1
    2 : block_2
      : block_3
    4 : block_4
      : block_5
    6 : block_6
    OTHER : block_other

The compiler tallies up the cases and produces an internal FLE (force less-than-or-equal) value to make sure the branching is bounded.

The OTHER case, which is optional, could be expressed with OTHER or maybe ">". And the values can be implied sequentially, so they are not requisite. Might it be good to allow expected values (0,1,2...), but not require them?

The 2nd example which lists every value is easiest to read, but a pain to rearrange. The 1st example can be rearranged, but the case numbers are not immediately apparent. The 3rd and 4th examples show the optional numbering with different OTHER approaches.

Which is best, if any?
«134567

Comments

  • BeanBean Posts: 8,129
    I like the second example. If the blocks are long, it makes it very clear where you are.
    Also you could skip some numbers if you don't want anything to happen for them.
    The ">" selector looks a bit odd, but I guess you have to use something.

    Bean
  • cgraceycgracey Posts: 14,133
    Bean wrote: »
    I like the second example. If the blocks are long, it makes it very clear where you are.
    Also you could skip some numbers if you don't want anything to happen for them.
    The ">" selector looks a bit odd, but I guess you have to use something.

    Bean

    ">" is supposed to mean "out-of-bounds" or "greater-than".

    This is internally a jump table, so there are no dead spots, as each entry needs an address. I suppose I could have empty blocks vector right to the last terminator.
  • yetiyeti Posts: 818
    edited 2019-05-21 12:25
    The numbered list style looks good.
    Optionally being able to leave out some numbers may be ok, but totally unnumbered may be confusing for long lists.

    I remember having counted long "on var goto ..." lists far too often in that 80ers era of MSBASIC and friends...

    For the compiler listing the indices in the source is redundant but it may help spotting a forgotten "case" for the human and the compiler.
  • VonSzarvasVonSzarvas Posts: 3,272
    edited 2019-05-21 12:27
    I also like 2nd the best, for same reason. Clarity, especially when the blocks are long.

    Would another option be to accept optional range numbering?
    cast x
        0:   block_0
        1:   block_1
        2-4: block_2
        5:   block_3
        6,7: block_4
        8:   block_5
        9:   block_6
        ?:   block_other
    
  • evanhevanh Posts: 15,126
    edited 2019-05-21 12:37
    Is CASE already taken? doh!, yes. :)
    If it's slow why not replace it?
  • I have a trend to prefer the second example (straight-thru numbering) since one can immediately notice to where the # indexes are leading to, and also avoid commom errors during code edition, such as inserting another element at the table, without rearranging the indexes accordingly.

    Sure, one can solely rely on the odd or even-numbered indexes, but them it'll have to depend on the parser, in order to verify the consistence of the sequence; there would be some errors to check for and correct.

    Henrique
  • cgraceycgracey Posts: 14,133
    Thanks, Guys.

    I kind of like everything being numbered, as well, because it's immediately clear. It's just a pain to rearrange.

    I will see about doing what VonSzarvas says. It starts to get back to CASE functionality pretty quickly.

    You can also call methods with indexes: BaseMethod[index](params). This is a runtime thing, so you need to know what you're doing. Same with using method pointers, which also have indexes, by the way.
  • cgraceycgracey Posts: 14,133
    Yanomani wrote: »
    I have a trend to prefer the second example (straight-thru numbering) since one can immediately notice to where the # indexes are leading to, and also avoid commom errors during code edition, such as inserting another element at the table, without rearranging the indexes accordingly.

    Sure, one can solely rely on the odd or even-numbered indexes, but them it'll have to depend on the parser, in order to verify the consistence of the sequence; there would be some errors to check for and correct.

    Henrique

    If we had a smart editor, it could dynamically show the numbering without your needing to type it. Maybe in the future.
  • cgraceycgracey Posts: 14,133
    evanh wrote: »
    Is CASE already taken? doh!, yes. :)
    If it's slow why not replace it?

    CAST is a faster/simpler cousin to CASE. CASE evaluates every case, whereas CAST just jumps. CASE is needed sometimes, while CAST is much more efficient in cases where an integer succession exists.
  • RaymanRayman Posts: 13,797
    Maybe just call it "Jump" instead of cast? Cast means something else entirely to me...
  • How about calling this "CASET" or "CASE TABLE" instead of "CAST" (which could easily be confused with C or BASIC "CAST", which converts between types)?

    Even better might be to recognize a restricted set of CASE and automatically use a jump table if the cases are simple enough (and disjoint). That's more work, but might be nicer for the users.
  • cgraceycgracey Posts: 14,133
    Rayman wrote: »
    Maybe just call it "Jump" instead of cast? Cast means something else entirely to me...

    My first impulse was to call it FORK, but that means multi-threading in C.

    JUMP might be best, actually.
  • cgracey wrote: »
    ...
    Which is best, if any?

    @cgracey, I would prefer something like jl(cast) var label.
    That way, since you have an jump-list's ending label, if others are in between these can be not considered and thus become optional, so anyone is free to write them or not.
    JL x other
        : block_0
        : block_1
        : block_2
        : block_3
        : block_4
        : block_5
        : block_6
    other: block_other
    
    JL x EndJL
        0: block_0
        1: block_1
        2: block_2
        3: block_3
        4: block_4
        5: block_5
        6: block_6
    EndJL: block_other
    
  • I like the idea of casting a net.... But could "CAST" be confused as an operation to change type ?

    Can't think of anything better really. Hmm.
    Maybe CASEn or CASEN (ie. CASE-Numeric)
  • cgraceycgracey Posts: 14,133
    ersmith wrote: »
    How about calling this "CASET" or "CASE TABLE" instead of "CAST" (which could easily be confused with C or BASIC "CAST", which converts between types)?

    Even better might be to recognize a restricted set of CASE and automatically use a jump table if the cases are simple enough (and disjoint). That's more work, but might be nicer for the users.

    Yes, I thought about making the compiler smart enough to compile this more-efficient method when circumstances allowed, but it will take some work and maybe new parsing approaches. I was thinking your compiler could probably handle that, easily.
  • BeanBean Posts: 8,129
    Chip,
    Unless "ON" has another meaning, I think "ON x" instead of "CAST x" would make more sense (at least to BASIC programmers).
    Just my opinion....

    Bean
  • cgraceycgracey Posts: 14,133
    One nice thing about having a uniquely-named instruction for this operation, is that people will use it with intent. They would more likely get the benefit from a uniquely-named instruction than a subtle use case of a singly-named instruction.
  • cgraceycgracey Posts: 14,133
    edited 2019-05-21 13:30
    Bean wrote: »
    Chip,
    Unless "ON" has another meaning, I think "ON x" instead of "CAST x" would make more sense (at least to BASIC programmers).
    Just my opinion....

    Bean

    I've just been searching and there's no ~4-letter word in English that means what we need a word to mean.

    "ON" is pretty good, but it's an awfully small word, almost gets looked past:
      on x
        0: block_0
        1: block_1
        2: block_2
        3: block_3
        4: block_4
        5: block_5
        6: block_6
        >: block_other
    
  • evanhevanh Posts: 15,126
    My query was because of the chosen name too. CAST is not a good choice.
  • cgraceycgracey Posts: 14,133
    edited 2019-05-21 13:31
    evanh wrote: »
    My query was because of the chosen name too. CAST is not a good choice.

    We need a word that means "pick one and do it".
  • cgraceycgracey Posts: 14,133
    What about PICK ?
  • How about "JMP"? It has the advantage that it's already a reserved word in Spin, so it won't break existing code.

    Another good choice might be "GOTO", which isn't a reserved word but is probably less likely to conflict with anything:
       GOTO x
         0: do_0
         1: do_1
         other: do_other
    


  • XPICK, YPICK; XJMP; YJMP (not to be confused with Z80's IX and IY-based indexing...)
  • BeanBean Posts: 8,129
    I like "PICK" almost as much as "ON" ;)

    Bean
  • Would this support cases when the index starts greater than zero ?
    In that case, using ">" may be confusing, as the index could also be less than minimum.

    OTHER or ? may suit both cases of less or more,
    As a shorthand I prefer "?". ie. something else or something unknown.

      on x
        2: block_2
        3: block_3
        4: block_4
        5: block_5
        6: block_6
        7: block_7
        8: block_8
        ?: block_other
    

  • How about "GOON" As in "Go On"
    GOON x
        2: block_2
        3: block_3
        4: block_4
        5: block_5
        6: block_6
        7: block_7
        8: block_8
        ?: block_othe
    
  • ersmithersmith Posts: 5,900
    edited 2019-05-21 14:52
    Please, let's not overload ? with more meanings -- it's already used in conditional assignment and random number generation. Using it as an alias for "other" will make parsing (and reading) code more complicated.

    "other" is already there, and is reasonably clear to the reader, so I think we should use it.

    I know that experienced Spin users like to save keystrokes, but it's a false economy -- code is read a lot more often than it is written, and having cryptic short aliases for everything makes it harder for new users to come to grips with code.
  • ersmith wrote: »
    Please, let's not overload ? with more meanings -- it's already used in conditional assignment and random number generation. Using it as an alias for "other" will make parsing (and reading) code more complicated.

    "other" is already there, and is reasonably clear to the reader, so I think we should use it.

    I know that experienced Spin users like to save keystrokes, but it's a false economy -- code is read a lot more often than it is written, and having cryptic short aliases for everything makes it harder for new users to come to grips with code.

    Agreed.
  • How about some variation of "Execute Index" ?

    Maybe "Exe#" or "Execute#" ??

    J
  • The > symbol has too many different meanings in spin.
    I agree about using OTHER: or even suggest ELSE:
Sign In or Register to comment.