2024-01-04 15:02:53 i realized that my recurse word doesn't work right in does> bodies when it occurred to me- is there any good reason to support recursion in forth? in other languages you use recursion as a roundabout way to access an abstract stack, but forth gives you direct access to a stack, so what's the point? 2024-01-04 16:20:00 What makes it not work right? 2024-01-04 16:20:35 Do you mean you can't include RECURSE direction in a DOES> body? 2024-01-04 16:20:52 Because it's slightly different somehow from a standard definition? 2024-01-04 16:22:58 s/direction/directly/ 2024-01-04 16:25:22 I don't have a recurse word. I can use labels as soon as they're defineD< so if I need "real" recursion I can just call the word. And if that happens immediately before ; it will get tail optimized to a jump. Additionally I have a flock of words that accomplish the same thing - the unconditional one is "me" and I also have numerous conditional variants on that. Those all use jumps, though. 2024-01-04 16:26:00 I don't know if I could use a me word in a does. body or not; I'm not sure if I've ever tried. Probably not, because there is no label at the beginning of that code to find in the dictionary, and that's how it figures out where to jump to. 2024-01-04 16:26:22 I'm thinking of doing it a different way in the next system, that likely could be made to work in does>. 2024-01-04 16:37:59 So is your problem that RECURSE doesn't know how to find the address to call, or is it deeper - is it just not possible to compile a standard call to that location for some other reason? 2024-01-04 16:39:20 I could probaby diddle with my system a bit and arrange for it to work - does> would need to store some address and possibly some status, so that the me words would know what to do in that situation. 2024-01-04 16:39:27 hmm... what is the definition of RECURSE in most forths? 2024-01-04 16:39:48 I think it just creates a call to the word being compiled. 2024-01-04 16:40:07 I mean the : of it 2024-01-04 16:40:15 And if that call turns out to be just before the ; then it should be tail optimizable as usual. 2024-01-04 16:40:31 Oh, not sure, but one way would be to use LATEST to find the definition you're working on. 2024-01-04 16:41:18 and RECURSE is an immediate word like IF ELSE and THEN 2024-01-04 16:41:23 LATEST and then whatever is necessary to make sure that's an xt, and then , that into the dictionary? 2024-01-04 16:41:33 Yes, it would necessarily be immediate. 2024-01-04 16:42:23 so DOES> might want to flip a boolean that RECURSE looks at 2024-01-04 16:42:28 zelgomer's problem is probably that his does> code isn't laid out like a standard : word. 2024-01-04 16:42:36 Possibly, yes. 2024-01-04 16:42:52 that's the sort of thing I'd need to do to support my me words in does> 2024-01-04 16:43:23 Actually it would be delicate in my case, because the me words aren't immediate. 2024-01-04 16:43:53 Their headers have a flag that tells the compiler to add an offset back to the start of word after them in the dictionary. 2024-01-04 16:43:58 to have RECURSE , in a word that looks at the returnstack to see whence execution came 2024-01-04 16:44:07 so my diddling would have to inform that code on what the right address was. 2024-01-04 16:44:36 ah, yes, another case where if RECURSE is itself a ; definition the return stack comes in handy. 2024-01-04 16:44:42 miss the point. i know what's wrong with my recurse, i can fix it if i want to. the question was, is there any reason to? is there any good reason to ever use recursive calls in forth? 2024-01-04 16:45:00 but that value on the return stack isn't necessarily the START of the word. 2024-01-04 16:45:09 It's not itself where you necessarily want to recurse to. 2024-01-04 16:45:22 No, i understood your question. 2024-01-04 16:45:40 I wouldn't want to give up recursion, but on the other hand I rarely do it. 2024-01-04 16:45:48 I generally loop. 2024-01-04 16:45:53 zelgomer: well that is a good question, depends on the code you write I suppose 2024-01-04 16:46:44 But I still have the same problem - my way of implementing those loops relies on the word having a normal header and structure in the dictionary. 2024-01-04 16:46:49 Zarutian_iPad: does it? that's what i'm getting at. i think that anything you write in forth using recursion can be very minimally changed into a loop 2024-01-04 16:48:09 could also make an argument the other way: is there any good reason to have loops in forth? because you could probably just as easily get by with a single looping word (maybe "again") which just restarts the current word 2024-01-04 16:48:50 KipIngram: hmm... what is on the returnstack when the DOES> portion runs? an xt of the CREATEd word or the caller of that word? 2024-01-04 16:49:33 zelgomer: Makes me think of https://dercuano.github.io/notes/forth-looping.html 2024-01-04 16:49:36 It's the next instruction pointer address WITHIN the calling word. 2024-01-04 16:49:47 it's not the beginning of any word. 2024-01-04 16:49:49 Er, https://dercuano.github.io/notes/forth-looping.html#addtoc_1 2024-01-04 16:49:51 zelgomer: you basically stumbled/toed on the compsci question regarding loops versus recursion 2024-01-04 16:51:17 zelgomer: btw, on fcpu-16 the only dynamic branch instruction is EXIT 2024-01-04 16:52:12 had to resort to stuff like : (JMP) R> @ >R ; to get even unconditional jumps 2024-01-04 16:52:57 I still think given what that address actually is some additional diddling around would be required. 2024-01-04 16:53:14 why? because I couldnt be arsed to figure out the circuitry to support immediate operands 2024-01-04 16:53:25 It does get you an address within the word you're wanting to invoke with RECURSE, but somehow you need to "back up' from there to the first address in the word. 2024-01-04 16:54:05 IIRC, my LATEST gives me a name pointer. 2024-01-04 16:54:50 hmm... DOES> flips the bool var and RECURSE then patches the emitted DOES> ? 2024-01-04 16:54:50 so i have to do something like LATEST CFA ( now I have an absolute address) , 2024-01-04 16:55:55 DOES> should save the next dictionary address in a variable, which is where the DOES> code will start. That's the target of the jump. 2024-01-04 16:56:01 And possibly set a mode. 2024-01-04 16:56:15 Then RECURSE will see that mode and address and compile a jump to that address. 2024-01-04 16:56:23 Even so, though, that's only tail recursion. 2024-01-04 16:56:26 It's not real recursion. 2024-01-04 16:56:32 the problem with my recurse is that latest isn't updated by does>. : foo create , does> recurse ; 0 foo bar bar ( <-- executes foo again instead of finitely recursing in bar ) 2024-01-04 16:56:56 s/finitely/infinitely/ 2024-01-04 16:56:57 Whether or not real recursion will work will depend on whether that address can have an xt, and I think that depends on the way you've implemented everything. 2024-01-04 16:57:26 I guess if that's a problem then RECURSE could also push a return address to the return stack at runtime. 2024-01-04 16:57:32 Getting messy, though. 2024-01-04 16:57:45 Push a return address and then jump. 2024-01-04 16:59:47 The core problem here is that the code after does> isn't really a definition. It doesn't have a header, and that may mean it doesn't have a CFA, the address of which would be an xt. 2024-01-04 17:00:07 And as usually my thinking here is tainted by me only ever having done indirect threaded systems. 2024-01-04 17:00:15 I imagine it would be quite different in a code threaded system. 2024-01-04 17:02:39 s/usually/usual/ 2024-01-04 18:08:24 zelgomer: Most Forth words have two fundamental pieces of information associated with them. They have to tell you a) where the data associated with the specific word instance is and b) where the code is that knows how to do something with that data. 2024-01-04 18:09:11 The thing that makes does> tricky is that it requires a third piece of information. You need a) the data associated with the instance, b) the code that tells how to run a sequence of addresses as code, and c) the location of that sequence of code. 2024-01-04 18:09:32 So the "basic design" of the system doesn't really support that three-item structure; it has to be kludged in somehow. 2024-01-04 18:10:06 It's a bit like you have to combine the effect of a variable with the effect of a colon definition into one item. 2024-01-04 18:11:06 Another way of thinking about it is that for most words the system expects item b in my first list to be actual machine code, but with does> you're trying to replace that with something like a colon definition itself, so one extra bit of hoop jumping is required. 2024-01-04 18:11:49 The only exception to that first list is primitives, which have only item b - just the code and no instance data. 2024-01-04 18:18:28 This covers some implementations of does> http://www.bradrodriguez.com/papers/moving3.htm 2024-01-04 18:34:39 I did it by giving the ultimately defined words two parameter field addresses instead of one in their header, and having such words trigger a "dodoes" bit of code rather than dovar or docol. 2024-01-04 18:35:06 dodoes just uses one of those addresses a la dovar and the other a la docol. 2024-01-04 18:38:36 It's helpful in my system that headers and bodies live in different region. By the time we execute does> when a new final word is being defined, all of the allot stuff has been run, so there's no telling what's going on in the body region. But the header region is still just like it was right after CREATE, so it's easy to add that extra required address. 2024-01-04 18:39:03 And when does> executes, the address of the code it needs to point to is on the return stack. 2024-01-04 18:40:04 CREATE has already set the dovar address, so I just pop that return stack item, , it onto the end of the header, and it's all done. 2024-01-04 18:40:20 Oh, and does has to switch the word's CFA from dovar to dodoes. 2024-01-04 18:41:45 So insofar as recurse goes, the LATEST header does contain the necessary information, but it's one notch further along in RAM (because the one you want isn't the data address CREATE populated - it's the one right after. 2024-01-04 18:42:14 So that flag we talked about would just tell me words to get the address from one half-cell past where it otherwise would. 2024-01-04 18:43:12 So I'd probably have CREATE set some variable to zero, and DOES. would set it to 4. And then I'd add that value to my target address when I added the offset for ME words. 2024-01-04 18:43:59 I should do that - it seems easy enough. I'd just never thought of it before. Which means I've never had cause to use a me word in a does> block. 2024-01-04 18:44:15 If I had it'd have blown up in my face. 2024-01-04 18:55:50 Another option would be to have does> swap those two addresses, so that the docol address was the first one. Modify dodoes to match. Then I wouldn't need that state awareness - me words would just naturally work. 2024-01-04 18:55:56 That's better. 2024-01-04 18:56:34 Then does> words will look naturally like colon definitions, but have that extra address in the header that dodoes "does something with." 2024-01-04 18:57:25 Then if I had RECURSE it would work just fine. 2024-01-04 19:08:04 i have already implemented does>. i don't know why you felt like you needed to tell me how it works 2024-01-04 19:14:01 I was mostly responding to GedaMo's comment, and then I slipped into "improve my own system" mode - sorry for thinking out loud. 2024-01-04 19:14:18 But... it will be a nice improvement, so I'm happy the whole discussion came up. 2024-01-04 19:14:37 I'd never recognized that there was a preference as to which way those addresses appeared in the headers. 2024-01-04 19:16:06 Anyway, you might find that if you adjusted a couple of things in your implementation then RECURSE would work in DOES> code. 2024-01-04 19:16:14 It seems pretty implementation dependent, though. 2024-01-04 19:17:18 Sorry, I wasn't really paying attention :P 2024-01-04 19:17:32 I think that kind of thing is pretty common in this channel. 2024-01-04 19:17:46 We pop in and out and don't always completely catch up. 2024-01-04 19:18:06 But overall I think we talk about pretty interesting stuff. 2024-01-04 19:36:40 It also hadn't occurred to me before how much easier separating headers and bodies makes it to implement create/does>. When the data region gets appended after the header, then it's a lot harder to add an extra item to the header. 2024-01-04 19:37:19 I actually say BUILDS> DOES> instead of CREATE DOES>, so I know right off that I need that special header. 2024-01-04 19:37:52 BUILDS> seems more descriptive to me. 2024-01-04 19:37:52 Wasn't it ? :P 2024-01-04 19:38:07 Well, not in my system, but I see what you're getting at. 2024-01-04 19:38:30 The stuff that pertains to building comes after BUILDS> and the stuff that pertains to doing comes after DOES>. 2024-01-04 19:39:00 So I think of them not as brackets but rather as 'pointing at' their associated stuff.