2026-07-14 14:01:25 Has anyone seen a Forth loop like DO that encodes the limit as a literal, like 0 FROM ... 50 TO repeatedly executes between FROM/TO until iterator is equal to 50 2026-07-14 14:01:39 Advantage is you don't need to store limit on return stack 2026-07-14 14:02:03 Disadvantage is you can't get/set the limit 2026-07-14 14:02:34 I guess is a bit pointless but it's a little easier to read in the case where the limits are literals 2026-07-14 14:10:42 Sounds like 0 >R BEGIN ... R@ 50 < WHILE , or something. (Assuming I is R@ ; no idea how common that is.) 2026-07-14 14:37:40 I used to be the R@ on most forths 2026-07-14 14:38:05 R@ was introduced so I didn't have to be the top return stack item 2026-07-14 14:38:36 But it used to be really standard I think that the top return stack items were K J' J I' I 2026-07-14 14:38:59 Which is pretty useful given this was before locals were a thing 2026-07-14 14:40:16 Where I' and J' are the limits for the inner and outer loop respectively 2026-07-14 14:40:51 Then everything changed when the semantics of LEAVE were updated to jump to the end of the loop, rather than just assigning I to I' 2026-07-14 14:41:25 Or I 1- maybe 2026-07-14 14:41:55 But making LEAVE jump means you need a destination address to jump to, and the easiest way to provide that is on the return stack 2026-07-14 14:42:35 I don't think it was worth it, LEAVE shouldn't jump, there's not much benefit for the cost 2026-07-14 18:52:51 I've been considering how to maximise self-similarity of the words in my forth kernel to make them easier to compress. I've been wondering if it makes sense to have some internal words that don't pop their arguments - let's call + that doesn't pop it's arguments (+) - and then you do : + (+) nip nip ; (or equivalent) to get the standard word 2026-07-14 19:37:40 it'll depend on if you actually have a use for words that leave arguments on the stack. 2026-07-14 19:37:44 When would a (+) that leaves the values be useful over a standard + ? 2026-07-14 19:38:10 ACTION has no issues with doing this, if it actually makes sense for the problems you are solving 2026-07-14 19:41:38 my thought process is that e.g. "over +" can be rewritten as "(+) nip", which is similar to the standard "(+) nip nip" 2026-07-14 19:43:01 that is, the purpose of "(+)" is to merge with stack operations as much as feasible 2026-07-14 19:43:27 If you have TOS reg then (+) is one instruction on e.g. x86 2026-07-14 19:43:34 As is NIP 2026-07-14 19:44:41 And if you are STC and can inline trivial stuff then : + (+) nip ; is identical to machine code 2026-07-14 19:45:42 if `over +` or `(+) nip` is a common enough idiom in your code, it might make sense. It really depends on a balance between your code, system, and underlying architecture. 2026-07-14 19:46:43 I'd be tempted to just write a primitive for this if I was using it frequently enough and was using an architecture with a rich instruction set 2026-07-14 19:47:32 It's not the kind of optimisation I'd focus on 2026-07-14 19:48:34 I think write an assembler and you can hand-write parts of your code, often for massive speedups, without compromising simplicity of the kernel 2026-07-14 19:49:11 well, crc, my personal goal for my forth implementation is to use it for sizecoding, and while I could likely implement such a primitive, the idea is more the pattern of two-operand words such as +, with stack manipulation words 2026-07-14 19:50:15 Sounds legit 2026-07-14 19:52:10 I find myself questioning the standard advice to consume input, I find very often code is simpler when you aren't consistent 2026-07-14 19:53:33 littering some code with "dup" doesn't feel very concatenative :p 2026-07-14 19:53:41 Like : BYTE ( addr - addr+1 byte ) DUP 1+ SWAP C@ ; 2026-07-14 19:53:55 I find useful for getting bytes from an array 2026-07-14 19:54:09 Or : BYTE COUNT ; 2026-07-14 19:54:55 They do the same thing but the latter isn't very clear 2026-07-14 19:55:50 And : STORE ( addr byte - addr+1 ) OVER C! 1+ ; 2026-07-14 19:56:45 And notice how one mentions size and the other doesn't, that's Forth consistency ;) 2026-07-14 19:58:18 I do think "not consuming args" better fits the register machines that forth actually runs on 2026-07-14 20:01:40 The big reason to not consume args is to simplify or shorten code 2026-07-14 20:02:01 I think that's easy to defend 2026-07-14 20:13:37 ACTION uses `fetch-next` and `store-next` as equivalents to `byte` and `store` in those examples; both are quite useful 2026-07-14 20:15:24 Nice 2026-07-14 20:17:20 lofty: re: `dup`, in a quick scan of one of my projects, I have 26,358 words used in all definitions. 502 of them are `dup` or `dup-pair`, so under 2% 2026-07-14 20:20:03 total use of primitive stack shufflers in this application is 1266 uses, so under 5% 2026-07-14 20:22:52 Very nice