Skip to content

Instantly share code, notes, and snippets.

@greggirwin
Created June 4, 2019 19:52
Show Gist options
  • Save greggirwin/4dd6deb56dcba704bf6d418aff244373 to your computer and use it in GitHub Desktop.
Save greggirwin/4dd6deb56dcba704bf6d418aff244373 to your computer and use it in GitHub Desktop.
Red Incr/Decr
Re: WRT: func ['name content][]
WRT incr {
The most common case will be to change state, but incr does add meaning, and has
benefits, in my mind, when used with scalars.
- By default, there is no step value, so you can't get the + 1 part wrong.
- Incr is often used when looping, making loop variables stand out from other add
ops that might be in expressions.
- Incr generally means the step is small. Another mental hint.
- If we use a lit-word! param how do you use a computed incr arg?
- It's not a terrible thing to use lit-word! params. They are a tool. But they can
make you think a bit more, especially in mixed expressions. For incr that may
not be as much of an issue, but it may be used a lot, and that means that many
more cases where a non-evaluated arg isn't directly visible when reading code.
}
incr: function [
"Increments a value or series index"
value [scalar! series! any-word! any-path!] "If value is a word, it will refer to the incremented value"
/by "Change by this amount"
amount [scalar!]
][
amount: any [amount 1]
if integer? value [return add value amount] ;-- This speeds up our most common case by 4.5x
; though we are still 5x slower than just adding
; 1 to an int directly and doing nothing else.
; All this just to be smart about incrementing percents.
; The question is whether we want to do this, so the default 'incr
; call seems arguably nicer. But if we don't do this it is at
; least easy to explain.
if all [
integer? amount
1 = absolute amount
any [percent? value percent? attempt [get value]]
][amount: to percent! (1% * sign? amount)] ;-- % * int == float, so we cast.
case [
scalar? value [add value amount]
any [
any-word? value
any-path? value ;!! Check any-path before series.
][
op: either series? get value [:skip][:add]
set value op get value amount
:value ;-- Return the word for chaining calls.
]
series? value [skip value amount] ;!! Check series after any-path.
]
]
decr: function [
"Decrements a value or series index"
value [scalar! series! any-word! any-path!] "If value is a word, it will refer to the decremented value"
/by "Change by this amount"
amount [scalar!]
][
incr/by value negate any [amount 1]
]
w: 1
incr w
w
incr 'w
w
b: [1 2 3 x 4 y 5 z [6 7 8]]
incr b
b
incr 'b
b
incr 'b/1
b
incr 'b/x
b
incr/by 'b/y 2
b
incr 'b/z
b
incr 'b/z/1
b
o: object [i: 0 b: [a b c]]
incr 'o/i
incr 'o/b
o
v: 1.2.3
incr v
v
incr 'v
v
incr/by v 2.3.4
incr #"A"
incr 1:2:3
incr 1x2
incr 1%
decr 10%
i: 0
; i will now refer to 'i, just as if you'd done `i: 'i`
i: incr 'i
get i
@greggirwin
Copy link
Author

Lit-args, yes. The workarounds just aren't very nice.

% * int Seems to be fixed now. This code is quite old.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment