.BYTE[n] syntax

I want to put a number of parameters for program execution into the BYTE elements of a LONG array. Say Sequence[4]. Each LONG array element comprises 4 BYTEs, and I want to read and write to these BYTEs individually, something like:

Sequence[step].BYTE[param]:= value

So far I can only find LONGVAR.BYTE[n]:= value. Probably that can just be extended by adding 4 (BYTEs) to n to get me into the next LONG array element, ie. use LONGVAR.BYTE[n+4]:=value.
Am I right, or is there a more elegant (which in my world means descriptive and readable) way to do it?

Relend
«1

Comments

  • If you're using the bytes individually, why not declare the array as a BYTE array?
  • I could do that, but logically they are together; it represents a sequence with 4 byte-sized parameters for each step of the sequence. I suppose I am dreaming about Spin supporting multidimensional arrays.
    Erlend
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-15 - 18:15:35
    The form you want...
        byteValue := longVar[index].byte[n]
    
    ... doesn't work. (I wish it did).

    Here's what you can do to get around this limitation.
        byteValue := longVar.byte[(index << 2) + n]
    
    In this case you're treating an array of longs as an array of bytes. I do this in a couple programs.

  • Thanks. As always, good ideas in addition to being good ideas also makes me think one more time (even though I tend to overthink). Since easy readability is the main thing I will - as @ersmith suggests - instead use 4 byte arrays, and name each of them the name of the parameter that they represent.
    E.g.
    Duration[SeqStep]:= 47
    Speed[SeqStep]:= 20
    Temperature[SeqStep]:= 92
    Mode[SeqStep]:= 5
    
    Maybe this format even improves legibility.

    Erlend
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-15 - 18:33:38
    I seqStep is always the same (as above), you could create a long called sequence0 and then do the definitions like this:
      sequence0.byte[I_DUR] := 47
      sequence0.byte[I_SPD] := 20
      sequence0.byte[I_TMP] := 92
      sequence0.byte[I_MOD] := 5
    
    Where this can save time later is when you want to pull those four values. If they're in a single long, and you have these (global) variables:
      byte  duration
      byte  speed
      byte  temperature
      byte  mode
    
    ...you can do this:
      bytemove(@duration, @sequence0, 4)
    
    Mind you, this is a suggestion based on having no idea what your program is doing.

  • One approach I've used to achieve similar ends is to create a structure in DAT. Something like this.
    DAT
    dummy long 0   ' A long here assures long alignment of following bytes
    sequence        ' this creates a name, same address as duration0
    duration0 byte 0     ' the values can be initialized, persistent in eeprom
    speed0 byte 0
    temperature0 byte 0
    mode0 byte 0
    duration1 byte 0
    speed1 byte 0
    temperature1 byte 0
    mode1 byte 0
    ' ... etc.
    

    Then either refer to each by name,
    speed0 := 20
    or
    byte[@duration0][SPEEDIDX] := 20 ' CON SPEEDIDX=1
    or
    byte[@sequence][4*index + SPEEDIDX] := 20
    or
    longpacket := long[@sequence][index]
    The long value might be useful for something like a controller that requires fast transmission of the packets. When I've used this format, it's been for transmission of 100 byte packets via xBee, a structure with mixed header and data bytes, words longs, that are filled in by the program and then passed as a packet for transmission.
  • JonnyMac wrote: »
    I seqStep is always the same (as above), you could create a long called sequence0 and then do the definitions like this:
      sequence0.byte[I_DUR] := 47
      sequence0.byte[I_SPD] := 20
      sequence0.byte[I_TMP] := 92
      sequence0.byte[I_MOD] := 5
    
    Where this can save time later is when you want to pull those four values. If they're in a single long, and you have these (global) variables:
      byte  duration
      byte  speed
      byte  temperature
      byte  mode
    
    ...you can do this:
      bytemove(@duration, @sequence0, 4)
    
    Mind you, this is a suggestion based on having no idea what your program is doing.

    Not a bad suggestion based on having no idea of what my program is doing. It controls the brewing process of a coffee machine.
    For readability each step in the sequence has a name, presently as a {comment}, but the above approach means I could (and will) do it like this (showing only a few of the assignments I will use:
      preheat.byte[I_DUR] := 47
    ...
      prewet.byte[I_DUR] := 42
      prewet.byte[I_SPD] := 20
    ...
      preinfuse.byte[I_TMP] := 92
    ...
      mainbrew.byte[I_MOD] := 5
    
    and then
      bytemove(@duration, @preheat, 4)
    

    Elegance achieved!

    Erlend
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-16 - 15:35:27
    Since you're assigning hard values, I suggest you follow Tracy's suggestion and move those assignments into a DATA table:
    dat
    
    '' Brew step control values
    '' -- duration, speed, temperature, mode
    
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5
    
    With this style all your initial control values are in one place which makes editing easy, you can use bytemove to grab all four elements, or if you only need one of the bytes you can treat each stage like a simple array.
      duration := PreHeat[I_DUR]
    
    This gives you a lot of flexibility. If your program has an HMI that lets you change values, adding an EEPROM object will let you save those values such that they're available at next power-up. In my EE object that would look something like this:
      ee.wr_byte(@PreHeat[I_DUR], PreHeat[I_DUR])
    

    PS: I love coffee!
  • @JonnyMac Except this object is receiving a single command from the HMI (calling code), e.g. Espresso or Americano or some other variants of coffee, and then does a CASE selection of which set of values to assign to the sequence table that corresponds to the desired drink. As a user you don't get to set e.g. the duration, but you get to chose Espresso (short) or Americano (long), for instance. Also, I calculate the Preheat duration based on the delta t between the water in the heater, and the desired brewing temperature - it can vary.
    So I think the table needs to stay 'soft', agree?

    Love coffee too.
  • -or come to think of it, there will be 7-8 sets of parameters, representing 7-8 different types of coffees, so maybe put all 7-8 sets in DAT, and then somehow select which one the sequence execution code should use. Is there a neat trick for that?
    dat
    
    '' Brew step control values
    '' -- duration, speed, temperature, mode
    
    'Turkish
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Espresso
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Americano
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Long
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Dishwater
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Pumponly
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    
    'Heatonly
      PreHeat       byte    47, 20, 92, 5
      PreWet        byte    42, 20, 92, 5 
      PreInfuse     byte    47, 20, 92, 5 
      MainBrew      byte    47, 20, 92, 5 
    


  • Don't forget about the "little endian" where bytes are in the reverse order within longs. It's a trap if your are not aware of it.
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-17 - 05:06:46
    Is there a neat trick for that?
    If the number of phases for each coffee type are the same, you could do something like this -- first, fix up the table.
    dat
    
    '' Brew step control values
    '' -- duration, speed, temperature, mode
    
      CoffeeStyle   byte
    
    'Turkish
      PreHeat0      byte    47, 20, 92, 5
      PreWet0       byte    42, 20, 92, 5 
      PreInfuse0    byte    47, 20, 92, 5 
      MainBrew0     byte    47, 20, 92, 5 
    
    'Espresso
      PreHeat1      byte    47, 20, 92, 5
      PreWet1       byte    42, 20, 92, 5 
      PreInfuse1    byte    47, 20, 92, 5 
      MainBrew1     byte    47, 20, 92, 5 
    
    'Americano
      PreHeat2      byte    47, 20, 92, 5
      PreWet2       byte    42, 20, 92, 5 
      PreInfuse2    byte    47, 20, 92, 5 
      MainBrew2     byte    47, 20, 92, 5 
    
    'Long
      PreHeat3      byte    47, 20, 92, 5
      PreWet3       byte    42, 20, 92, 5 
      PreInfuse3    byte    47, 20, 92, 5 
      MainBrew3     byte    47, 20, 92, 5 
    
    'Dishwater
      PreHeat4      byte    47, 20, 92, 5
      PreWet4       byte    42, 20, 92, 5 
      PreInfuse4    byte    47, 20, 92, 5 
      MainBrew4     byte    47, 20, 92, 5 
    
    'Pumponly
      PreHeat5      byte    47, 20, 92, 5
      PreWet5       byte    42, 20, 92, 5 
      PreInfuse5    byte    47, 20, 92, 5 
      MainBrew5     byte    47, 20, 92, 5 
    
    'Heatonly
      PreHeat6      byte    47, 20, 92, 5
      PreWet6       byte    42, 20, 92, 5 
      PreInfuse6    byte    47, 20, 92, 5 
      MainBrew6     byte    47, 20, 92, 5 
    
    
    var
    
      byte  duration, speed, temperature, mode
      byte  style, phase, ofs
    

    And now you can grab the phase variables like this:
      ofs := (style << 4) + (phase << 2)
      bytemove(@duration, @CoffeeStyle+ofs, 4)
    
  • ErlendErlend Posts: 605
    edited 2020-01-17 - 07:52:49
    JonnyMac wrote: »
    Is there a neat trick for that?
    ...

    And now you can grab the phase variables like this:
      ofs := (style << 4) + (phase << 2)
      bytemove(@duration, @CoffeeStyle+ofs, 4)
    

    I like that, I'll just add some comment headers for better readability:
    'Turkish               Duration     Speed        Heat    Mode
      PreHeat0      byte    99,          20,          92,    5
      PreWet0       byte    42,          20,          92,    5 
      PreInfuse0    byte    47,          20,          92,    5 
      MainBrew0     byte    47,          20,          92,    5 
    
    And the program will calculate preheat duration and move that number into the Duration byte of Preheat (showed as 99 here).
    Erlend

    Edit
    This code grabs all 4 bytes/parameters, right? So it is more like:
      ofs := (style << 4) + (phase << 2)
      bytemove(@parameter4set, @CoffeeStyle+ofs, 4)
    
    -and then I have to extract byte 0, 1, 2, 3 to get the individual parameters.
  • Just to finish off:
    PUB SetDuration(style, value) | ofs
    
       ofs := (style << 4)
       byte[@CoffeeStyle][ofs]:= value
    
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-17 - 18:21:05
    -and then I have to extract byte 0, 1, 2, 3 to get the individual parameters.
    Remember that when the Propeller makes variable address assignments they go in the order that your variables appear in the listing. Note that I added four stage variables (all bytes) to the global space. If duration is at address n, then speed is at address n+1, and so forth. Now we can move four bytes from the table to those four variables with bytemove. No further extraction is required.

    Each coffee style requires 16 bytes (four phases of four bytes), so you can update elements like this:
    var
    
      byte  duration, speed, heat, mode                             ' phase variables for given style
      byte  style, phase
    
    
    dat
    
      CoffeeTable           byte
    
    'Turkish                        Duration    Speed       Heat        Mode
      PreHeat0              byte    99,         20,         92,         5
      PreWet0               byte    42,         20,         92,         5 
      PreInfuse0            byte    47,         20,         92,         5 
      MainBrew0             byte    47,         20,         92,         5 
    
    
    pub get_phase(style, phase)
    
    '' Copy phase values to global variable set
    
      bytemove(@duration, @CoffeeTable[(style << 4) + (phase << 2)]
    
      
    pub set_duration(style, phase, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 0] := value
    
    
    pub set_speed(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 1] := value                                             
                                                                     
    
    pub set_heat(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 2] := value
    
    
    pub set_mode(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 3] := value
    
    Some people don't like one-line methods, but I think it's okay because it will enhance the readability of the code that calls these methods. To help with the set_ methods I would suggest named constants for each style and phase:
    con
    
      #0, TURKISH, ESPRESSO, AMERICANO, LONG_BREW, DISH_WATER, PUMP_ONLY, HEAT_ONLY
      #0, PREHEAT, PREWET, PREINUSE, BREW
    
    Now you have method calls that look like this:
      set_duration(TURKISH, PREHEAT, 45)
    

    Note that I updated the name of the table -- because simple things like that double entendre make me laugh.
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-17 - 18:30:33
    If your program is going to have some kind of HMI you might find this simple trick useful, too.
    dat
    
      StyleName             byte    "Turkish   ", 0
      {x11}                 byte    "Espresso  ", 0
                            byte    "Americano ", 0
                            byte    "Long Brew ", 0
                            byte    "Dish Water", 0
                            byte    "Pump Only ", 0
                            byte    "Heat Only ", 0
    
      PhaseName             byte    "Time ", 0
      {x6}                  byte    "Speed", 0
                            byte    "Heat ", 0
                            byte    "Mode ", 0
    
    
    pub style_name(style)
    
      return @StyleName(style * 11)
    
    
    pub phase_name(phase)
    
      return @PhaseName(phase * 6)
    
    These methods return a pointer for a .str() method. By padding the end of short strings with spaces so that all are the same length, finding the address of the string in a table is easy and the display cleans itself.
      display.set_cursor(STYLE_X, STYLE_Y)
      display.str(style_name(style))
    
  • Also, though performance isn't necessarily the goal here, you could change
    CoffeeTable           byte
    

    to
    CoffeeTable           long
    

    which will effectively make your table long-aligned. Then you can use longmove() instead
  • JonnyMac wrote: »
    Note that I updated the name of the table -- because simple things like that double entendre make me laugh.



  • There are some great tips in this discussion which I am putting into my local Spin notes/example directory, the only tip I can add is the following:

    Whatever coding method(s) you use, one liners, DATs, etc... be sure to document the heck-out-of-it so even a newbie could understand it, perhaps in a separate document for the entire project, so your source file doesn't get overwhelmed. While you are working the project now it all seems so simple and elegant. But if you are like me, going back to the code/project n months later after working with other languages, you will keep asking yourself "What am I doing this for?" "How does this work?" Never assume "Oh, I'll remember that trick..."

    Case in point for us old farts who grew up using Korn shell in UNIX environments, you would frequently see these kinds of incantations (this is a simple one compared to some I've seen/created):
    ENVIRON=$HOME/.kshrc                                    export ENVIRON
    ENV='${ENVIRON[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'       export ENV
    

    And all it does is determine whether or not the shell is running interactively or not.

  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-17 - 20:17:09
    which will effectively make your table long-aligned. Then you can use longmove() instead
    I did a quick test. The target variables are bytes, and if the first doesn't fall onto a long boundary, longmove doesn't work correctly. Am I missing something?

    You're right that longmove is faster (by about 1.8us), but I don't think manipulating the code to use it is worth the trouble in this particular case.
  • SeairthSeairth Posts: 2,408
    edited 2020-01-17 - 23:43:42
    That's the reason for changing the "byte" to "long" above. That will ensure that the table (and each "row") starts on a long boundary.
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-18 - 00:03:39
    The issue is with the destination values; if the first is not aligned on a long boundary, longmove does not work correctly (even with the table alignment corrected). In my demo, I am moving four bytes from the table to four byte-sized global variables.

    I just ran another test. It seems like longmove masks off the lower two bits of the destination address before running. This can cause a problem if the destination is not long-aligned, because the longmove will overwrite values that precede the destination.

    Test data:
    dat 
    
      Table         long
                    
      Values        byte    10, 20, 30, 40
    
    
    var  
    
      byte  z, y, x
      byte  a, b, c, d
    
    Without the z, y, and x line, longmove(@a, @Values, 1) works fine. Adding variables ahead of a is an issue -- and trying to force alignment into a group of byte variables (not DAT) elements would probably confuse newcomers.

  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-18 - 01:15:19
    Sorry, @Erland, I missed on of your posts vis-a-vis values that you want to indicate have to be calculated. To indicate that in the table, I tend to use -1, like this.
    dat
    
      CoffeeTable           byte
    
    'Turkish                        Duration    Speed       Heat        Mode
      PreHeat0              byte    -1,         20,         92,         5
      PreWet0               byte    42,         20,         92,         5 
      PreInfuse0            byte    47,         20,         92,         5 
      MainBrew0             byte    47,         20,         92,         5
    
    What will actually be stored for the PreHeat0 duration is 255 (the lower eight bits of -1). After you've moved a phase into the global variables, you might do something like this:
      get_phase(style, phase)
      if (duration & $80)
        duration := calculate_duration
    
    This allows the table entry of -1 to be easier for humans to spot. Yep, it's wading through the minutia, but sometimes we do this to create high-quality code.
  • SeairthSeairth Posts: 2,408
    edited 2020-01-18 - 13:21:36
    [quote="JonnyMac;c-1487431"]The issue is with the destination values; if the first is not aligned on a long boundary, [b]longmove[/b] does not work correctly (even with the table alignment corrected).[/quote]

    Good point! I wasn't thinking about the destination.


    (edit: the mobile interface quotes differently, which makes things hard to read. updated now that I'm at a computer. no substantive changes.)
  • ErlendErlend Posts: 605
    edited 2020-01-18 - 10:03:21
    JonnyMac wrote: »
    If your program is going to have some kind of HMI you might find this simple trick useful, too.
    dat
    
      StyleName             byte    "Turkish   ", 0
      {x11}                 byte    "Espresso  ", 0
                            byte    "Americano ", 0
                            byte    "Long Brew ", 0
                            byte    "Dish Water", 0
                            byte    "Pump Only ", 0
                            byte    "Heat Only ", 0
    
      PhaseName             byte    "Time ", 0
      {x6}                  byte    "Speed", 0
                            byte    "Heat ", 0
                            byte    "Mode ", 0
    
    
    pub style_name(style)
    
      return @StyleName(style * 11)
    
    
    pub phase_name(phase)
    
      return @PhaseName(phase * 6)
    
    These methods return a pointer for a .str() method. By padding the end of short strings with spaces so that all are the same length, finding the address of the string in a table is easy and the display cleans itself.
      display.set_cursor(STYLE_X, STYLE_Y)
      display.str(style_name(style))
    

    Thanks. I actually do this in my code, but I wish I could use the obj#value syntax to access and maintain those strings where they belong - in the brew object.

    Erlend
  • JonnyMac wrote: »
    -and then I have to extract byte 0, 1, 2, 3 to get the individual parameters.
    Remember that when the Propeller makes variable address assignments they go in the order that your variables appear in the listing. Note that I added four stage variables (all bytes) to the global space. If duration is at address n, then speed is at address n+1, and so forth. Now we can move four bytes from the table to those four variables with bytemove. No further extraction is required.

    Each coffee style requires 16 bytes (four phases of four bytes), so you can update elements like this:
    var
    
      byte  duration, speed, heat, mode                             ' phase variables for given style
      byte  style, phase
    
    
    dat
    
      CoffeeTable           byte
    
    'Turkish                        Duration    Speed       Heat        Mode
      PreHeat0              byte    99,         20,         92,         5
      PreWet0               byte    42,         20,         92,         5 
      PreInfuse0            byte    47,         20,         92,         5 
      MainBrew0             byte    47,         20,         92,         5 
    
    
    pub get_phase(style, phase)
    
    '' Copy phase values to global variable set
    
      bytemove(@duration, @CoffeeTable[(style << 4) + (phase << 2)]
    
      
    pub set_duration(style, phase, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 0] := value
    
    
    pub set_speed(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 1] := value                                             
                                                                     
    
    pub set_heat(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 2] := value
    
    
    pub set_mode(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 3] := value
    
    Some people don't like one-line methods, but I think it's okay because it will enhance the readability of the code that calls these methods. To help with the set_ methods I would suggest named constants for each style and phase:
    con
    
      #0, TURKISH, ESPRESSO, AMERICANO, LONG_BREW, DISH_WATER, PUMP_ONLY, HEAT_ONLY
      #0, PREHEAT, PREWET, PREINUSE, BREW
    
    Now you have method calls that look like this:
      set_duration(TURKISH, PREHEAT, 45)
    

    Note that I updated the name of the table -- because simple things like that double entendre make me laugh.

    Yes. I prefer a very visual style of code, so I always use CONs for constants. Nice also that the TURKISH... constants can be accessed from the calling (top level) code.
    Is
    bytemove(@duration, @CoffeeTable[(style << 4) + (phase << 2)]
    
    superior to my own
    byte[@CoffeeStyle][ofs]:= value
    
    when duration is the only parameter I ever need to change?

    Erlend
  • JonnyMac wrote: »
    Sorry, @Erland, I missed on of your posts vis-a-vis values that you want to indicate have to be calculated. To indicate that in the table, I tend to use -1, like this.
    dat
    
      CoffeeTable           byte
    
    'Turkish                        Duration    Speed       Heat        Mode
      PreHeat0              byte    -1,         20,         92,         5
      PreWet0               byte    42,         20,         92,         5 
      PreInfuse0            byte    47,         20,         92,         5 
      MainBrew0             byte    47,         20,         92,         5
    
    What will actually be stored for the PreHeat0 duration is 255 (the lower eight bits of -1). After you've moved a phase into the global variables, you might do something like this:
      get_phase(style, phase)
      if (duration & $80)
        duration := calculate_duration
    
    This allows the table entry of -1 to be easier for humans to spot. Yep, it's wading through the minutia, but sometimes we do this to create high-quality code.

    I stand corrected :) Promise never again to use 99, when -1 is indeed the closest you can get to a nil character.
    Erlend
  • There are some great tips in this discussion which I am putting into my local Spin notes/example directory, the only tip I can add is the following:

    Whatever coding method(s) you use, one liners, DATs, etc... be sure to document the heck-out-of-it so even a newbie could understand it, perhaps in a separate document for the entire project, so your source file doesn't get overwhelmed. While you are working the project now it all seems so simple and elegant. But if you are like me, going back to the code/project n months later after working with other languages, you will keep asking yourself "What am I doing this for?" "How does this work?" Never assume "Oh, I'll remember that trick..."

    Case in point for us old farts who grew up using Korn shell in UNIX environments, you would frequently see these kinds of incantations (this is a simple one compared to some I've seen/created):
    ENVIRON=$HOME/.kshrc                                    export ENVIRON
    ENV='${ENVIRON[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'       export ENV
    

    And all it does is determine whether or not the shell is running interactively or not.

    Agree. I love it when I can tease the Masters into sharing gold nuggets like these. Agree 2. I always try to write the code so that it is easy to read (also for non-Spin'ers), and even inefficient if that is what it takes to make it easy on the eye. This particular project has been idle for several years, but thanks to myself (!) I had no problem picking it up and now bringing it to completion.

    Erlend
  • JonnyMacJonnyMac Posts: 6,577
    edited 2020-01-18 - 15:39:04
    Is
    bytemove(@duration, @CoffeeTable[(style << 4) + (phase << 2)]
    
    superior to my own
    byte[@CoffeeStyle][ofs]:= value
    
    when duration is the only parameter I ever need to change?
    The bytemove line above grabs for values from the table; the other line puts a value into the table. Both actions have their place, I'm sure, so given the assignment I would do somthing like this that allows me to get or update any individual table value:
    pub get_duration(style, phase)
    
      return CoffeeTable[(style << 4) + (phase << 2) + 0]
    
    
    pub set_duration(style, phase, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 0] := value
    
    
    pub get_speed(style, phase)
    
      return CoffeeTable[(style << 4) + (phase << 2) + 1]
    
    
    pub set_speed(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 1] := value
    
    
    pub get_heat(style, phase)
    
      return CoffeeTable[(style << 4) + (phase << 2) + 2]
    
    
    pub set_heat(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 2] := value
    
    
    pub get_mode(style, phase)
    
      return CoffeeTable[(style << 4) + (phase << 2) + 3]
    
    
    pub set_mode(style, stage, value)
    
      CoffeeTable[(style << 4) + (phase << 2) + 3] := value
    
    As I stated earlier, I don't mind one-line methods because they can make the mainline code much easier to understand. By wrapping these lines in methods it also allows you to move the table and the methods to another object if you choose.
  • JonnyMac wrote: »
    Is
    bytemove(@duration, @CoffeeTable[(style << 4) + (phase << 2)]
    
    superior to my own
    byte[@CoffeeStyle][ofs]:= value
    
    when duration is the only parameter I ever need to change?
    The bytemove line above grabs for values from the table; the other line puts a value into the table. Both actions have their place, I'm sure, so given the assignment I would do somthing like this that allows me to get or update any individual table value:

    The trouble of posting too late at night. I do know this, now I know it double.

    Erlend
Sign In or Register to comment.