00:00:00 --- log: started forth/18.10.02 00:51:19 --- join: ncv (~neceve@unaffiliated/neceve) joined #forth 01:02:00 --- quit: wa5qjh (Remote host closed the connection) 01:03:53 --- join: wa5qjh (~quassel@175.158.225.198) joined #forth 01:03:54 --- quit: wa5qjh (Changing host) 01:03:54 --- join: wa5qjh (~quassel@freebsd/user/wa5qjh) joined #forth 01:26:39 --- join: siraben (~user@unaffiliated/siraben) joined #forth 02:04:19 --- quit: ashirase (Ping timeout: 252 seconds) 02:07:04 --- join: ashirase (~ashirase@modemcable098.166-22-96.mc.videotron.ca) joined #forth 02:24:31 --- quit: dave9 (Quit: dave's not here) 02:35:30 --- quit: wa5qjh (Remote host closed the connection) 02:42:50 I actually think I may have been helped, when it came to getting my head around Forth, that I had no inclination to try to "make it fit" some pre-existing knowledge structure in my head. 02:43:13 The way it worked didn't have to be some particular concept I'd learned. 02:43:36 I just took it for exactly what it was - the stuff I read said it did this, so that's what it did. 02:43:52 Immediate words actually run at compile time. Ok, fine. That's perfectly clear. 02:44:55 You guys talk about "closures" - I'm not even really sure what a closure is. But the notion that this words runs the minute it's encountered in the source, whereas that one runs later when I execute the compiled word - that's simple enough that I don't need any "framework" to house it in. 02:45:46 One of you even told me a couple of weeks ago what a closure it, and I'm still not sure, because it was expressed in terms of other abstract concepts. 02:45:59 It's like there's a circularity in all that and I haven't "picked into it" yet. 02:47:05 I run into the same thing when I try to study abstract algebra and stuff. There are rings and fields and a whole bunch of other concepts, and they're all defined in terms of one another. I haven't yet found the right spot to start taking apart the Gordion's knot. 02:47:17 closure is a function with a hidden state (it closes over variables) which is preserved between function calls 02:47:48 But Forth is SIMPLE. It doesn't need a framework. To me it's just about what machine instructions are running when. 02:48:09 So it's code with some data. 02:48:12 The data persists. 02:48:27 yes, it's a code with some data, exactly 02:48:43 So I don't really feel a huge need for that to have a name. :-) 02:49:12 if you were the only programmer in the world it surely wouldn't 02:49:34 I'm not trying to be critical - I'm actually a huge fan of "well-organized" knowledge. I watch a lot of physics videos, and I'm always trying for that next level of "fundamentalism." 02:49:46 So it's great - seriously. I just never learned it that way. 02:50:09 KipIngram: For closures it depends on the language. 02:50:15 Probably because I'm not really a programmer by education - I've just picked up programming along the way. 02:50:19 I'm a hardware guy by training. 02:50:40 most abstractions may be refuted that way. function is a code with a call stack. why name it? 02:51:22 classes on theoretical level are a bunch of functions closed over the object data 02:51:35 KipIngram: How would I add local variables to words? 02:51:54 Say I wanted a constant value but not pollute the word list, just HIDE it afterwords? 02:52:03 Well, that's been done in a number of ways. First off, every word has local variable space - it's called the stack. 02:52:12 I take it what you're going for is to be able to name stack slots. 02:52:17 Yes. 02:52:17 Refer to them by name. 02:52:27 Which implies you have words that can access particular stack slots. 02:52:34 I've added a "frame" concept to my Forth. 02:52:38 Like PICK? 02:52:47 A word can define a stack frame, which basically just sets a "frame pointer." 02:52:53 And I have words to access offsets from that pointer. 02:53:01 Words deeper in the call stack can use those words. 02:53:22 The stack pointer may be different, but the frame pointer isn't, so the whole slew of words can reference the same data using the same words. 02:53:30 Hm. 02:53:33 I just called them 0@ 1@ 2@ 0! 1! 2! etc. 02:53:47 Now, I've thought about a system that will allow me to use names to reference those words. 02:53:51 Based on stack comments. 02:53:52 But these pointers are relative to where the top of the stack was when that word was invoked, yes? 02:54:01 ( a b c -- d e) 02:54:19 That naming system would be an editor level thing. 02:54:21 So if A called B and A referred to stack position 2, it means relative to ITS "top of stack"? 02:54:30 No, that's how I first wrote it. 02:54:32 And B's position 2 could be different 02:54:39 And the stack comment connection really works better with that. 02:54:45 Later I introduced the frame pointer. 02:54:52 Sorry I mean A and B are words, not stack elements 02:54:56 I have words {{ and }} - they open and close a frame. 02:55:00 Ah. 02:55:08 Inside, those 0@ and so on words will always refer to the SAME DATA. 02:55:15 By the way, I've just implemented DOES>, how should I test it? 02:55:23 I just realized that occasionally I have tasks that can't get by with just 1 or 2 stack elements. 02:55:42 I've tried the classic : CONSTANT WORD CREATE DOCOL_H , DOES> @ ; and it works, but what other examples are there? 02:55:46 I really prefer "the Forth way," where you factor factor factor so that you don't need to go deep into the stack. 02:55:51 Right. 02:55:54 But ONCE IN A WHILE I think you just can't do that. 02:56:05 Maybe I'm just not a good enough Forth programmer yet. 02:56:11 There's always an offset relative to the current stack pointer 02:56:23 I've only had to use this 2-3 times in my system, but man, when I do use it it sort of saves the day. 02:56:31 Naming stack elements? 02:56:39 No, just having a frame. 02:56:55 That's a very similar concept to how closures are done in most languages 02:56:58 I just write a little note down to the side telling me what piece of data is where in the frame, and then I used the numeric-based words. 02:57:05 3@ 2+! etc. 02:57:22 Can you give an example of how you use {{ ? 02:57:33 Uh, yeah, let me find one. 02:57:40 Ok thanks. 02:58:05 DOES> was a little complicated to trace through initially but it worked out. 02:58:15 : EXPECT OVER 0 SWAP C! 1 0 {{ (EXPECT) }} 4 DROPS 02:58:16 Not sure how to use it though. 02:58:24 So it first sets up some important data on the stack. 02:58:25 What does enclosing in parens mean? 02:58:27 (EXPECT) 02:58:31 Then runs {{ 02:58:34 It's just a name. 02:58:54 Usually just a way to say "I had some set up to do, but most of this is a loop." 02:59:05 The "meat" of EXPECT is in (EXPECT). 02:59:09 Two separate words. 02:59:17 So now, inside (EXPECT), I've got a LOT of factoring. 02:59:27 Lots of definitions that wind up having no names. 02:59:31 Hmm. Is there a smaller example? 02:59:33 But just exist to keep the code short and simple. 02:59:41 Say I wanted to compute b e + but I had the stack like this: a b c d e 02:59:42 Well, when the code is small you generally don't need a frame. 02:59:55 An offset would do? 02:59:59 Well, ok, sure. 03:00:24 a b c d e {{ 3@ + }} 03:00:39 Inside the frame, e is at 0, d is at 1, c is at 2, b is at 3. 03:00:44 Ah I see 03:00:44 a is at 4. 03:00:56 So you have bound variables. 03:00:59 Can you nest them? 03:01:10 I supported up to 6, and instead of writing f@ which took a depth parameter I hard-coded depths into the words, for efficiency. 03:01:17 Yes, they can be nested. 03:01:27 Outer ones reside on the return stack. 03:01:31 So you can't use them interactively. 03:01:43 Because {{ bombs your return stack. 03:02:01 Execute it interactively and your system will crash. 03:02:04 4 3 2 1 0 {{ 3@ {{ 3@ }} }} . . would print out 3 then 2? 03:02:20 Uh, yes, that looks right. 03:02:26 I haven't had to nest them. 03:02:27 I mean a stack with 4 3 2 1 0, not added in that 03:02:35 Yes. 03:02:35 I see. 03:02:53 This is really like a closure 03:02:59 Ok. 03:03:34 So see, how you could provide some source-level mechanism that let you alias those 3@ 2@ words, with "names" if you wanted to, but all you're doing is affecting the readability of your code. 03:03:38 To give an example ((lambda (x y) (+ x y)) 2 3) reduces to (+ 2 3) then 5 as x is bound to 2 and y is bound to 3 03:03:44 It would still COMPILE to the number-based words. 03:03:47 Similar to your nesting 03:04:09 So does 3@ depend on the stack at compile time or run time? 03:04:24 Run time. 03:04:33 Whatever the frame pointer has in it at run time. 03:04:43 It just offsets 3 cells from the frame pointer and fetches that. 03:04:47 How do I implement concurrency/coroutines in Forth? 03:05:19 Well, exactly what do you mean? Sorry - terminology again. Multiple tasks? 03:05:36 --- join: john_metcalf (~digital_w@host109-149-153-210.range109-149.btcentralplus.com) joined #forth 03:05:44 Yeah. For instance, say I'm running one of your frames and I want to pause execution on that to a different frame 03:05:44 I have task blocks and process blocks. 03:05:55 Naming things are hard 03:06:01 At any time the address of the base of the currently executing task is held in a register. 03:06:13 And that task's owning process is pointed to by the first cell of the task block. 03:06:22 So I get at task variables by offsetting from the register. 03:06:30 And get at process variables by offsetting from [register] 03:06:47 I have three classes of variables in my Forth: system, process, task. 03:06:59 The only difference is what gets added to the variable "address." 03:07:03 They're all stored as offsets. 03:07:06 From "something." 03:07:09 Hm. I see. 03:07:15 system vars are offset from the base of the whole system in RAM. 03:07:24 Process vars offset from base of process block. 03:07:32 Task vars from base of task block. 03:07:50 Your Forth system is an entire OS? 03:07:58 I have task vars to serve as register save locations - to switch tasks, I save the registers, reload the task register, load the registers, continue. 03:08:16 I mean for it to be, yes. 03:08:21 Ah I see, so you save registers and can restore state. 03:08:30 It currently runs only under MacOS, but I'm "doing things" that are os level functionality. 03:08:34 And intend to port it to bare metal. 03:08:55 Yes, ultimately a few register values are the important state. 03:09:12 targets me at the correct memory blocks, points at the right code to execute, points to the right stacks, etc. 03:09:19 Change the registers correctly, you change the context. 03:09:28 So what can I use DOES> for now that I have it? 03:09:42 :-) 03:09:43 ^ I'll take a further look at multiple threads sometime 03:09:45 Anything you like. 03:09:54 Can you give some examples? 03:10:00 Maybe from your system 03:10:36 Well, I don't actually use it much. And haven't implemented it in this sytem yet. But gosh, let's see. 03:10:45 Trying to think of something interesting. 03:11:03 Say you have a piece of hardware out there. 03:11:32 And there are a series of things it can do, and you make it do those things by writing a string of bytes to a register. 03:11:51 So you could define a word CONTROL 03:11:55 No - COMMAND 03:12:02 So that you could say this: 03:12:12 COMMAND ALPHA 03:12:31 That creates the word ALPHA, and when ALPHA is executed it will stream to the hardware. 03:12:57 Ah, so making new words based on the current stack context? 03:12:57 : COMMAND , , , , DOES> ...code... ; 03:13:14 When ALPHA gets run, there will be the address where you ,'d those bytes on the stack. 03:13:29 So ...code... would fetch those four cells and write them to the hardware. 03:13:38 Probably in reverse order, so that you could WRITE THEM in the right order. 03:13:50 Sorry - 03:13:52 Right. 03:14:01 : COMMAND CREATE , , , , DOES> ...code... ; 03:14:06 Gotta have the CREATE 03:14:30 Hmm. In my Forth create takes a string pointer and a length to create the word, so I write WORD CREATE DOCOL_H 03:14:56 where DOCOL_H makes the docolon header like "call docol", and the address following the "call" instruction is overriden when DOES> runs 03:14:57 So if you make a whole bunch of those commands, they all "do" the same thing, but they have different data stored in their parameter fields. 03:15:04 Right. Sharing code. 03:15:38 --- quit: nighty- (Quit: Disappears in a puff of smoke) 03:16:07 KipIngram: Ok. I think I get DOES>. How about something like POSTPONE? 03:16:21 POSTPONE just delays execution one level. 03:16:28 Is that not the same as [COMPILE] ? 03:16:40 If you POSTPONE an immediate word, you basically just remove its immediacy. 03:16:46 You compile it - not run it. 03:16:58 Ah, so you append "if" to the definition but not compile it to zbranch ... 03:17:01 And if you postpone a non-immediate word, instead of running when you run that definition, it compiles it. 03:17:21 Hm? The non-immediate word doesn't run anymore? 03:17:32 Or is it just compiled like normal? 03:17:36 : ALPHA POSTPONE + ; 03:17:45 Now when you run alpha it will COMPILE +. 03:17:50 To whatever the end of the dictionary is then. 03:17:55 SEE ALPHA -> : ALPHA + ; right? 03:17:59 This used to be called COMPILE 03:18:05 : ALPHA COMPILE + ; 03:18:09 I think that's more readable. 03:18:24 So when I run alpha it will do something like ' + , ? 03:18:25 But they also had [COMPILE] to cover immediate words. 03:18:36 So they unified those into one word POSTPONE, which the two behaviors. 03:18:50 Yes, exactly. 03:18:52 Something like that. 03:19:06 Ok. What other things should I implement? 03:19:14 Useful standard structures? 03:19:36 :-) Well, I'm not sure what you've implemented and what you haven't. Those are two of the most important "fringe things," I think. 03:19:51 I've added some things not in usual Forths. 03:19:57 Do you have any kind of output formatting? 03:20:06 I supported something similar to C format strings. 03:20:36 Forth is traditionally weak in handling strings, arrays, and othe rsuch structures. 03:20:43 You might like something to help out in that area. 03:21:01 But that winds up involving some sort of memory management - you need a dynamic place to keep that stuff. 03:21:01 KipIngram: Here's my current word list https://github.com/siraben/ti84-forth/blob/master/DOCUMENTATION.md 03:21:08 So you're stepping pretty far from "real Forth." 03:21:17 Yeah I'm trying to implement ." but it's crashing when I run it in a compiled word 03:21:22 Ok. Let me get some coffee and I'll take a look. 03:21:33 Well, ." should be immediate. 03:21:49 If you run it interpreteting, it takes what follows in the input stream and prints it. 03:21:55 Right, I have that part. 03:22:11 But if you run it compiling, it needs to compile (.") and then put the string in compiled code memory after (.") 03:22:19 (.") prints it from there and steps the IP over it. 03:22:32 Be right back. 03:22:41 Alright. I'll take another stab at it. 03:22:46 Does your (.") move the IP? 03:23:00 Because when (.") runs it's pointing to the string, and you'll crash if you don't reposition it. 03:23:21 So there's a word called LITSTRING which can be used to add string literals to words: 03:23:43 ... | LITSTRING | 5 | h | e | l | l | o | NULL | ... 03:24:27 It should leave the address of the start of "hello" onto the stack, so I might follow it up with PUTLN, which prints a NULL-terminated string followed by a new line. 03:25:38 Ah I must be compiling it wrong... I need to keep track of the string length and then back-fill the length count. 03:25:53 Or maybe just omit the length entirely. 03:27:06 Yeah, there's really no more to it than what I wrote above - you probably just fubared the implementation. You'll make it work. 03:27:11 Ok, finding your word list now. 03:27:12 KipIngram: Re: formatting things, this reminds me of one of the features the Haskell language where it excels in which you can create your own data types and tell the compiler how to format them when printing 03:27:41 KipIngram: It's this one: https://github.com/siraben/ti84-forth/blob/master/bootstrap.fs#L28 03:27:46 Yes. 03:27:57 The indentation is like that because I pasted it into an asm file so I needed to reduce whitespace 03:28:02 Is there a pretty printer for Forth? 03:28:10 Sorry - that yes was for your question about compiling (.") 03:28:15 Right 03:28:25 You compile (.") then copy the string after that. 03:28:45 Yeah it'll be fixed soon 03:28:45 So when execution reaches (.") it not only prints the string, but also pushes the instruction pointer past the end of the string. 03:29:16 Ah, I just remembered that a good feature to have is 32 bit numbers. 03:29:19 Just like how (lit) puts the number on the stack and nudges IP past it. 03:29:24 It's just a long literal. 03:30:02 KipIngram: Right. lit does that 03:30:25 What's ASK do? 03:30:45 Oh I should have removed that, it just printed out a string "Press a key..." 03:30:49 Used it during testing 03:30:56 Ok. 03:31:19 It's hard to look at a list like that and click to "what might be missing." Looks like a pretty reasonable list. 03:31:20 So how would I implement 32 bit numbers? With 2 stack elements? 03:31:27 Yes. 03:31:33 And it's kind of tedious and annoying. 03:31:52 Traditional Forth makes a double entry like that if you include a decimal point in the number. 03:31:59 Location of the decimal point is irrelevant. 03:32:21 So 12345. 1.2345 and 123.45 all give you exactly the same thing. 03:32:21 Since it's a Forth on the calculator it would be a crime to not be able to add numbers > 65535 03:32:28 I see. 03:32:46 I'll need to look into the TI 84 ROM calls, there's quite a bit for floating point and so on 03:32:48 So once those two cells are on the stack, you have no idea how they cot there. 03:32:51 Displaying them as well 03:32:54 12345. 03:32:58 and 0 12345 03:33:00 give you the same thing. 03:33:07 Ok. 03:33:09 So + can't just "know you entered a double." 03:33:15 You have to have D+ or something. 03:33:20 Of course, yes. 03:33:23 And then the whole suite 03:33:28 Yeah. 03:33:34 My system is 64-bit - I passed on doubles. 03:33:34 D* D/ DMOD etc 03:33:42 Instead I'm letting decimal point designate "flaot." 03:33:47 Ah, jealous. 03:33:51 64 bits is a lot 03:33:55 Converts the number to floating point and leaves it on the FPU stack. 03:34:01 Yes, it's nice. 03:34:39 So in my case decimal location does matter. 03:34:51 12.3 and 1.23 are different by a factor of 10. 03:35:05 What's sorely missing is a screen editor 03:35:14 Yes, but you can write one. 03:35:16 I plan to. 03:35:26 It'll just use ANSI controls. 03:35:38 Oh, I have a command history in mine. 03:35:45 Apparently the calculator limits program sizes to 8K + a bit, so I'll need to read more on how the calculator stores that 03:35:57 I can navigate back through previous command lines and re-issue them, edit them and re-issue, etc. 03:36:03 And I DID nest frames. 03:36:07 Ah, Having that would be nice 03:36:12 Like a shell. 03:36:13 EXPECT has a frame in it, and QUERY also has one. 03:36:16 Yes. 03:36:27 It behaves largely like bash history, but not quite. 03:36:34 bash history has a weirdness I wasn't willing to tolerate. 03:36:54 If you navigate back in bash, edit a line and hit enter, you get that as your new line, and the old line is still back there unchanged. 03:37:14 Would Boyer–Moore be too much or am I just fine with a naive string searching algorithm? 03:37:15 But if you navigate back, change a line, and NAVIGATE AWAY FROM IT (not enter), it CHANGES THE HISTORICAL LINE. 03:37:17 I hate that. 03:37:26 Once you hit enter on a line it should never change as a history item. 03:37:33 Oh, you can change the history? 03:37:39 In bash you can, yes. 03:37:43 I consider it a bug. 03:37:53 I plan to support some regular expression capabilities. 03:37:54 I thought it reissues the command as a new one, no? 03:38:06 If you hit enter without leaving the editied line, yes. 03:38:08 But try it. 03:38:08 Or maybe I'm just too used to Zsh 03:38:09 03:38:22 Navigate back, diddle a line, then navigate forward again and do something. 03:38:28 Navigate back and see what tha tline looks like now. 03:38:31 The one you diddled. 03:38:46 Oh wow 03:38:52 YEAH. 03:38:59 Mine doesn't do that. 03:39:18 The history should be WHAT WAS EXECUTED. 03:39:24 In Zsh it just creates a new entry 03:39:29 Right. 03:39:47 That's the thing, you can do as you please in Forth. 03:39:57 I suspect there are some similarities between command history and a screen editor. 03:40:10 With a screen editor you just have more than one line visible, right? 03:40:16 But it's otherwise a similar structure. 03:40:19 Right. 03:40:28 Why did you choose to write it in nasm, macOS? 03:40:29 So I expect some code sharing there. 03:40:53 My IBM-issued computer is a Mac; nasm was just the first thing I got my hands on that seemed to be willing to work for me. 03:41:04 I think I'm going to have to switch to gas for this Cortex M4 port. 03:41:42 What's the last Forth standardization? 03:42:03 I heard something the other day about a 2012? 03:42:06 But I don't really know. 03:42:23 Seems to be more of an issue with Forth, people want different things all the time. 03:42:31 I think these things that are "missing" from Forth (string handling, commmand history, etc.) are all things that involve some complexity and require some kind of dynamic memory management. 03:42:41 Forth traditionalists just don't want to go there - too much complexity. 03:43:09 That command history involves a big buffer (obviously) and some fairly involved linked data structures. 03:43:25 Still looking for Forth Fundamentals, hm. 03:46:06 So my primary impetus for the stack frame thing was that command history. 03:46:13 I see. 03:46:16 Here I am, accepting a string from the keyboard. 03:46:26 Already a bit of an involved task, if you want to support cursor control and so on. 03:46:34 And now I want to add a whole other dimension to that. 03:46:40 Complicated data structure to navigate, etc. 03:46:51 So I would need to "pause" execution of reading the string 03:47:01 I just wound up with five or six or seven things on the stack, all of which I needed somewhat smooth access to. 03:47:13 That would require some restructuring because when a string is being read, nothing else can run. 03:47:13 Doing it with standard stack operations was a NIGHTMARE. 03:47:26 ^in my implementation 03:47:52 Right - when I first started this my quick and dirty "get it going" thing was to just do a MacOS "get string" syscall. 03:47:58 So obviously I had no control over that. 03:48:01 I took what MacOS gave me. 03:48:12 To take control I had to switch to getting individual keystrokes. 03:48:21 Implemented the "structure" myself. 03:48:31 Ah, that's how mine works. One key at a time. 03:48:47 It's the only way to really have things the way you want them. 03:49:01 And QUERY provides access to the command history, but EXPECT does not. 03:49:01 Especially because there weren't keys for characters like ! @ / \ etc. 03:49:08 Those keys just do nothing in EXPECT. 03:49:41 So I have a lower level word _READ. 03:49:47 KipIngram: Do you have a TI-84 calculator by any chance? 03:49:49 It handles reading a string and can be "resumed." 03:49:57 If it sees a key it doesn't know how to handle, it returns. 03:50:07 Since you're on a Mac you would be able to flash my program to your calculator, if you wanted. 03:50:09 Its caller can supply the handling and resume _READ. 03:50:24 I don't have a calculator these days. 03:50:33 Use an HP 42S emulator on my phone. 03:50:47 Ah hm. My string reader just asks for characters until a newline is hit. 03:50:57 Ignoring unprintable keys etc. 03:51:05 Right. 03:51:30 My _READ handles horizontal cursor controls. But if it sees vertical cursor controls it returns, with the terminating keystroke on the stack. 03:51:37 Caller can do something with that if it wants to. 03:51:47 QUERY does - navigates the command history. 03:51:55 EXPECT just ignores them and resumes _READ. 03:52:17 KipIngram: Here is the key code -> character conversion table 03:52:23 https://github.com/siraben/ti84-forth/blob/master/forth.asm#L1113 03:52:54 I use termios calls to dick my keyboard around so that it's fairly raw. 03:52:58 There's a $00 byte which corresponds to key code 5, the ENTER key. The GETS routine detects that and NULL-terminates the buffer. 03:53:16 I still get ASCII values, but for example all of ctrl-A through ctrl-Z will return a byte to me, 1-26. 03:53:41 I suppose I could add special byte values like $01 $02 $03 $04 for the arrow keys and dispatch on those 03:53:48 I defeated all of the "special handling" that systems typically give some of those. 03:54:24 Chasing down the right system calls on the Mac for that was a bit of an ordeal. 03:54:33 What documentation did you use? 03:54:34 Apparently Apple doesn't want people making system calls. 03:54:42 Wants them to use some thing called IOKit. 03:54:50 I just found a list online. 03:54:55 I have it bookmarked, probably. 03:55:03 There's not a lot of good stuff out there on that. 03:55:19 --- join: nighty- (~nighty@s229123.ppp.asahi-net.or.jp) joined #forth 03:55:20 TI provides a equates file for ROM calls 03:55:21 https://github.com/alberthdev/spasm-ng/blob/master/inc/ti83plus.inc 03:55:32 There's quite a bit of a community around TI-84 asm 03:55:39 I don't understand why Apple would be so snobby about it. 03:55:45 I'd imagine most people on macOS would use a compiler anyway 03:55:50 Why are the system calls THERE if they're not meant to be used? 03:56:12 Modern software industry - obsessed with abstraction. 03:56:21 Why do undocumented instructions exist in the Z80? 03:56:24 Or other chips for that matter? 03:56:38 I assume they're "inadvertent." 03:56:45 Just by-products of the hardware design. 03:56:55 Or in the case of Intel chips, they contain backdoors! 03:57:05 Yeah, no kidding. 03:57:10 That's kind of ridiculous. 03:57:28 It's evil. 03:57:48 Any other handheld microcomputers? 03:58:28 Is that a question for me? 03:58:34 In general, but sure. 03:58:52 I'm trying to think of interesting targets to port to later 03:59:09 Hey... how about a washing machine? 03:59:31 Forth would be great for running appliances. 03:59:36 Robotics in general, I think. 03:59:43 Classic Forth example. : WASHER WASH SPIN RINSE SPIN ; 03:59:55 Ah, I should investigate the robot cortex at my school 04:00:03 I currently write C code and compile to it 04:00:28 Here's the Cortex M4 I'm targeting: 04:00:46 https://learn.adafruit.com/introducing-adafruit-itsybitsy-m4/overview 04:01:02 But I wouldn't be gaining much I suppose. The compiler and library supports a lot of features, especially things like non-blocking tasks, threads, locks and so on 04:01:05 $15, and yet 20x the power of my first IBM PC AT that I bought back in 1985. 04:01:14 More than 20x. 04:01:24 20x the clock speed, but 32-bits instead of 16/8. 04:01:25 Oh my calculator is overpriced for sure then. 04:01:38 I had to pay something like $200 04:01:39 That was an 8088-based machine; 16-bit internal architecture but an 8 bit external bus. 04:01:55 Well, those old calculators are collectibles. 04:02:27 Mandatory for high schools and universities nowadays, it's crazy. 04:02:50 siraben: My MacOS thing here uses 64-bit stacks / data, but the "virtual machine internals" are 32 bits. 04:02:56 So it's a 64/32 bit system. 04:03:04 On that Cortex board I'm planning 32/16. 04:03:11 So it's a 16 bit chip? 04:03:19 Oh 32 bit 04:03:33 32 bit chip, but sort of RAM limited environment, so 16 bit internals will keep me small. 04:03:46 Is it possible to run that off a battery? 04:03:53 Say a single AAA 04:04:01 I'll left shift CFAs and stuff two bits before using them as addresses, so they'll cover the whole RAM. 04:04:15 I don't know what voltage it needs, but they sell a little lithium battery you can use with it. 04:04:25 It may need more than one AAA cell provides voltage-wise. 04:04:39 If Forth is to be used for appliances, it would be good to have it networked 04:04:39 There's probably a picture of the battery on that page somewhere. 04:04:46 Yes. 04:05:02 Ultimately I'm planning Bluetooth support with self-forming mesh networks. 04:05:04 So I could define something like : NIGHT WINDOWS CLOSE DOOR LOCK BOILER OFF ; 04:05:16 I've got direct work experience that's applicable there, from the seismic industry. 04:05:29 RIGHT. 04:05:38 Forth makes perfect sense to replace the current badly-headed IoT scene 04:05:42 I want to be able to have a flock of these things, mesh networked, that I can treat as a single integrated system. 04:05:53 I'm surprised it hasn't been done more 04:05:59 Mesh networking makes sense 04:06:04 I mentioned yesterday possible commercial stuff, like lab instrumentation? 04:06:15 Well, I'd want all of my instruments to be aware of one another, and willing to function as a system. 04:06:32 In that seismic work we had tens of thousands of nodes in our mesh network, and they synchronized their clocks. 04:06:34 So what would you recommend for a chip that I could port forth to? Arduino? 04:06:41 The ItsyBitsy M4 Express? 04:06:50 At the hardware level - they'd pull their clock frequencies a little bit until they all were phase locked. 04:07:02 Well, I certainly like that Itsy right now. 04:07:07 It has ALL the makings. 04:07:21 So how do you communicate with it? A serial terminal? 04:07:26 Doesn't have any bluetooth, but I'll add that later on a board of my own. 04:07:34 Yes, they have it set up pretty nice. 04:07:42 You can run Linux screen to get a session on it. 04:07:54 It fires up with a Python interpreter, but you can put it in boot loader mode and replace that. 04:07:55 By the way, did you have to implement arithmetic operations or were there opcodes for the chip? 04:08:05 It shows up as a disk drive on your desktop - you can just replace a file. 04:08:12 Ah I see. 04:08:23 There are opcodes. 04:08:39 For u/mod I had to write a few lines of code. 04:08:58 Is the Z80 still used and when is it useful? 04:09:03 It has a pretty reduced instruction set 04:09:07 So my goal will be to replace CPYTHON.UF2 with FORTH.UF2. 04:09:15 Then when I screen into the thing it will be my Forth talking back to me. 04:09:33 I don't think you'd find it in heavy use any more. 04:09:38 2 MB is plenty for Forth, right 04:09:39 ? 04:09:46 Oh god yes. 04:09:52 :) 04:09:54 That Itsy has 192k of RAM, and that is a gorgeous plenty. 04:10:09 I expect to be able to do a whole slew of concurrent processes on that. 04:10:35 By the way, how are you handling segfaults and the like in your Forth? 04:10:39 Do you do stack underflow checks? 04:11:33 I underflow check after each word is executed in INTERPRET. 04:11:41 So the INTERPRETER does that. 04:11:48 It doesn't happen within the execution of a compiled definition. 04:11:57 And if I segfault I restart the program. :-) 04:12:19 I would like to learn how to catch that and handle it myself, but that's for the future. 04:12:46 Ultimately I suppose it's a good tradeoff to make the programmer responsible for things, if the language is good as well 04:12:48 : INTERPRET ?DPAGE FIND IF DEF ELSE NUMBER THEN ?STACKS ME ; 04:12:57 ?STACKS does the underflow check. 04:13:06 Is that your entire INTERPRET? 04:13:10 Yes. 04:13:19 I've tried to factor well. 04:13:29 If NUMBER fails, what happens? 04:13:30 I don't have a single definition that runs more than 60 characters or so. 04:13:41 How about something like SEE? 04:13:52 You get an error - an error message is printed and it runs error recovery and QUITs. 04:14:07 I have it designed so that error recovery will restore the state that was extant at the beginning of the line. 04:14:11 Ah, out of all the things, I still have yet to implement proper number reading in my base interpreter! 04:14:15 It's not a WARM reset like in most Forths. 04:14:16 So this: 04:14:22 1 2 3 4 5 bad_word 04:14:33 will leave me with an empty stack - the 1 2 3 4 5 are "restored away." 04:14:34 But this: 04:14:37 1 2 3 4 5 04:14:38 bad_word 04:14:48 will still leave me with 1 2 3 4 5 on the stack. 04:14:48 WARM/COLD resets, what are they? 04:14:52 I see. 04:15:10 COLD is a TOTAL reset - in my case it jumps to the entry point of the whole system and it's all initialized again. 04:15:19 WARM resets data and return stacks. 04:15:23 QUIT resets return stack only. 04:15:44 COLD resets the dictionary. 04:15:47 WARM and QUIT don't. 04:15:48 Data being the words defined in current session? 04:15:53 When you said WARM resets data 04:15:59 I meant the data stack. 04:16:02 Empties it. 04:16:03 Ah I see. 04:16:27 How is your development process like for your Forth? Are you editing it within itself at this point? 04:16:34 My error recovery (which is non-standard) images the entire process to a snapshot. 04:16:49 If INTERPRET succeeds (exits normally), nothing is done with the image. 04:16:59 But any error causes me to copy the image back to the process / task space. 04:17:08 That's how it restores everything so cleanly. 04:17:13 Ah. I also have an image-like feature which is all the new words defined, locations of HERE and LATEST pointers 04:17:19 Right. Recovery isn't that hard. 04:17:24 If my line does something "out of process" (say I stream a message to another process) that's not unwound. 04:17:38 There's no way too - in a multi-tasking system the message may have been received and acted on already. 04:17:42 to 04:18:12 I learned on my last go round that there are some very subtle things that can go wrong on error. 04:18:23 Especially when you're changing vocabularies, defining new words, etc. 04:18:31 I was constantly realizing I'd failed to save/restore something. 04:18:37 So this time I sledge hammered it. 04:18:51 Save and restore every heap page the process is using. 04:19:24 It's not the most efficient thing in the world, but it's only done when a human is typing stuff. 04:19:50 I'm going to set it up so that for loading code from disk it will do error recovery if I have edited the source since the last successful compile. 04:19:50 Forth turned out to be really fast for a lot of things 04:20:05 But whenever a block successfully compiles, a flag will get set that says "you don't need to error recovery this." 04:20:17 "Known good code." 04:20:35 Yes. It has a bit of overhead - NEXT is pure overhead. 04:20:37 I had a program where it was copying/reading/displaying 768 bytes with each keypress (the interactive memory viewer) and noticed no lag at all. 04:20:39 But it's small and fast. 04:20:43 Right, for most things. 04:20:46 Right. 04:21:00 And it lets you create new primitives for the few cases where you can't tolerate even that overhead. 04:21:05 I plan a profiling system. 04:21:27 Ultimately I'll need to create a way to test all my words 04:21:32 Or most of them 04:21:45 Oh, in that definition of INTERPRET, ?DPAGE checks to see if I have room to compile a word remaining in the current definition heap page. 04:21:52 If I don't, it will move me to a new heap page. 04:22:01 If that happens mid-definition, it compiles a jump to the new page. 04:22:12 Have you used Forth for practical purposes, say in your home? 04:22:53 No, not in my home. But I did a consulting practice for a few years, and one of my projects was to "modernize" an old but well-loved pick and place machine, the Quad IVc from Quad Systems. 04:23:10 It ran a DOS-based interface; client dealt in used PnP's and wanted a Windows thing for it. 04:23:26 I designed a new motion control board for the thing, and it ran pForth via a network socket. 04:23:35 GUI over on the Windows box communicated with that. 04:23:39 Eventually that would be cool, if I could find an embedded device, add Bluetooth peripherals and so on to make those smart homes 04:23:57 Yes, that's in the ballpark of where I'm headed too. 04:24:00 I want a "core." 04:24:14 I just can't get over how amazing Forth is 04:24:14 A core bit of circuitry, running a good clean Forth system, that I can build anything around I want. 04:24:18 Right. 04:24:36 It's really a pretty marvelous demonstration of how simple things can be, in this age of bloat and complexity. 04:24:52 I agree. 04:24:53 I think the showcase example is Chuck Moore himself. 04:25:03 He wanted to design his own chips, to take his ideas to the hardware level. 04:25:14 So he did - and he wrote his own system for designing those chips, from scratch. 04:25:16 In Forth. 04:25:29 The chip layout stuff, the simulation stuff, the whole nine yards. 04:25:40 With NO commercial off the shelf CAD tools. 04:25:54 I suppose Emacs could be considered bloated 04:25:55 For a hardware guy like me, that's like god-status. 04:26:05 lmao 04:26:12 You get the understatement award of the day. 04:26:21 Haha 04:27:31 Moore said that he could make a change to his chip design, trigger compile, and it was ready to simulate before he could get his finger off the enter key. 04:27:44 He set it up so that he was compiling the *design of the chip*. 04:27:51 Re Emacs: I chose it ultimately because of its extensible nature, it's one bloated tool or several bloated tools with no coherent links, personal preferences I suppose. 04:27:54 That's cool. 04:27:58 I used to use emacs. 04:28:09 What made you stop? 04:28:22 I switched to vim, primarily because I got hold of a Linux emulation environment for my android tablet, and it offered vim but not emacs. 04:28:29 When did you last use it? 04:28:36 I also felt like vim had a slightly larger "mind share" in the community. 04:28:37 I thought Termux supports Emacs as well, no? 04:28:43 Uh, probably five years ago? 04:28:47 Mind share? 04:29:00 I didn't see that it did when I was trying to use it. 04:29:03 But I found Termux later. 04:29:07 This was a different one. 04:29:11 Ah I see. 04:29:12 Termux is FANTASTIC. 04:29:25 It "Just Works" (tm). 04:29:36 So what do you mean by "mind share"? 04:31:59 Larger fraction of people using it, perhaps more certainty of future development, etc. 04:32:17 But that may have just been me rationalizing the decision - the real reason was that Linux environment. 04:32:25 I think that one was called Terminal IDE. 04:32:38 Written by a guy handled Spartacus Rex. 04:33:10 I think vim and emacs are both entirely competent and reasonably graceful editors. 04:33:16 I don't get into the holy wars. 04:33:26 Yeah, it's personal preference. 04:33:37 I think emacs has slightly better "time motion efficiency." 04:33:47 Especially if you swap ctrl and capslock. 04:33:53 I was using tmux + Vim for a while before Emacs 04:33:54 That helps on vim too. 04:34:04 I've never used tmux - I hear it's good. 04:34:09 It's like Screen 04:34:09 screen has been adequate for my needs. 04:34:15 Do you know about mosh? 04:34:28 I've heard of it. 04:34:41 It's the niftiest package in the world as far as I'm concerned. 04:34:51 I do a ton of stuff via ssh console sessions. 04:34:55 Mosh makes them seem local. 04:35:08 Interesting, how? 04:35:10 I can sleep my computer, resume later, and it just re-connects me without batting an eye. 04:35:37 And no need to set it up on the server side? 04:35:38 DRive through a bad connectivity area - ssh will drop you and you have to re-establish. 04:35:41 Mosh just does it for you. 04:35:49 No, it does have a server side piece. 04:35:59 So you have to be able to sudo on your server. 04:36:03 That sounds similar to tmux/Screen sessions 04:36:16 Yeah, it's like it extends that over the network. 04:36:25 mosh+screen is a damn killer combo. 04:36:49 For this IRC stuff I run wee-chat curses on a seedbox in the Netherlands. 04:36:55 The admins there were willing to install mosh for me. 04:37:07 So it sits here in the top left corner of my console space, and it just never goes away. 04:37:11 It's "always on." 04:37:13 Ah so you're over SSH right now? 04:37:17 Yep. 04:37:25 I currently don't have a solution for always-on IRC myself 04:37:44 So I disconnect sometimes, might change later, who knows? 04:37:54 Yeah. 04:38:04 Well, take a look at mosh. I predict you'll appreciate it. 04:38:15 I'll take a look. 04:38:22 Once you've got it set up, it's as easy as ssh. 04:38:30 Just mosh user@server instead of ssh user@server. 04:38:51 I think a grad student at MIT or Harvard or something wrote it. 04:38:56 huh 04:39:03 On the subject of bloat, on a different area I appreciate more features in scientific/statistical computing, for instance Mathematica 04:39:15 I use Octave. 04:39:24 And I want to be able to do some of the things I do there in my Forth. 04:39:41 That's similar to "better string handling" - it involves some sort of a data pool. 04:39:42 At some point I'll need to switch out of Mathematica, I'm not even using it legitimately. 04:39:48 Perhaps Octave 04:39:59 But I want to be able to say [ 1 2 3 ] [ 4 5 6 ] + and get [ 5 7 9 ] 04:40:01 or something like that. 04:40:04 In Forth? 04:40:08 Yes. 04:40:19 Right. Maybe Forth needs a type system of sorts. 04:40:26 I anticipate an "add on" layer that I can compile that adds that capability. 04:40:32 I plan to do it with a "type stack." 04:40:35 But that would start to go against its philosophy, it would be interesting. 04:40:37 That's managed at compile time. 04:40:40 Yeah I thought of that as well, a type stack. 04:40:45 Types are checked at runtime 04:40:57 The compiler would know what the types at the top of the stack were, and would use that as part of the word search criterion. 04:41:04 So you could overload words with that. 04:41:05 It can be smaller than the actual stack because you don't need 4 billion types 04:41:09 Right. 04:41:23 And if you only consult it at compile time, it doesn't affect your run-time efficiency. 04:41:32 --- quit: ncv (Remote host closed the connection) 04:41:40 Ah so you introspect the compiled words and check if their types line up? 04:41:43 It means the stack effect of the words has to be documented in a system-aware way. 04:41:49 Right. 04:41:54 And say no-no to SMC 04:42:03 Or controlled SMC 04:42:07 Well, yes - when I search for the word I've just parsed, I look for one that expects the right things on the stack. 04:42:17 And that also tells me how it will change the stack, so I'm set up for the next word. 04:42:38 So something like * would have type annotation NUM NUM -> NUM , right? 04:42:44 But I don't want that in the core system. 04:42:47 Right. 04:42:51 Or swap: a b -> b a etc. 04:42:56 Correct. 04:43:10 That's a good idea. Type checking catches silly errors a lot. 04:43:12 The traditional Forth way would be to have a comment: 04:43:20 : SWAP ( a b -- b a) ... ; 04:43:23 Yeah, why not have the comment be functional? 04:43:42 I thought it was a type annotation the first time I saw Forth 04:44:07 Something like : SWAP T[ a b -- b a ] would be good 04:44:13 I think there is a lot of potential power in harnassing that. 04:44:22 Without making it "not Forth anymore." 04:44:24 Where "a" and "b" denote type variables, standing for any type 04:44:38 Forth has a lot of functional programming-like ideas 04:44:40 Yes. 04:44:45 Concatenation is composition 04:45:55 What about adding new types and structures? 04:45:55 I've been occasionally pondering that arena for several years. I'll get around to it eventually. 04:46:05 I think it can still definitely be Forth---perhaps even better. 04:46:17 --- join: ncv (~neceve@unaffiliated/neceve) joined #forth 04:46:18 Because you reduce errors without adding much more complexity. 04:46:21 Perhaps. We're getting dangerously close to another holy war, though. 04:46:24 Right. 04:46:26 Which holy war? 04:46:48 Well, hard-core Forth people are opposed to anything even coming close to "types." 04:47:07 In some ways I *am* a hard core Forth person, but I'm not entirely closed-minded either. 04:47:17 I guard the runtime efficiency pretty closely. 04:47:19 Well, they can be useful. There should be a way to turn it off at any point 04:47:25 Right, adding runtime overhead is bad 04:47:38 Yes - it just won't "be there" in my core system - you'd load source to engage it. 04:47:42 Just run a new interpreter. 04:47:49 When you're done, drop back to the old one. 04:48:08 Have you heard of the language Joy? 04:48:13 No. 04:48:22 www.latrobe.edu.au/humanities/research/research-projects/past-projects/joy-programming-language 04:48:27 It's inspired by Forth 04:48:28 Feel-good name, though. :-) 04:48:36 Haven't used it myself, but interesting ideas there. 04:49:01 DEFINE square == dup * . 04:49:08 You've heard me mention a "heap." A lot of the things that I'd like to do will require a real, full-on heap. 04:49:15 But I didn't want to weave such a thing into my core system. 04:49:25 So what I have now is a very simple heap that allocates fixed-size pages. 04:49:37 So there can't be any fragmentation - no garbage collection needed. 04:49:40 A heap being just free RAM memory? 04:49:42 It grows upward in memory. 04:49:53 I imagine I'll eventually implement a "real" heap that grows downward from the top. 04:50:01 Yes, and a way of allocating it. 04:50:11 I'm glad that garbage collection is not used a lot in Forth, and memory management is quite predictable. 04:50:17 I have words (HEAP) and (-HEAP) that allocate and free a block. 04:50:32 Ah, since you're on an OS 04:50:40 But I want to keep all of a processe's heap pages on a list, for (among other things) killing the process. 04:50:54 So HEAP and -HEAP use (HEAP) and -HEAP and add management of that list. 04:50:57 I've just begun writing embedded, so a lot of OS stuff is still over my head 04:51:15 (HEAP) and (-HEAP) are EXTREMELY simple. 04:51:25 When I free a page, I put it on a free list. 04:51:31 How big is a block or page? 04:51:37 When I allocate a page, I check the free list first; if it's empty I nudge a "top pointer" up a page. 04:51:50 At the moment I've got it set to 1k. 04:52:03 It was originally 64k, and everything about a process lived in one of those blocks. 04:52:06 Ah so it's the block/page in your Forth system, not the OS? 04:52:12 That was fine on the Mac, where I have an effectively infinite amount of RAM. 04:52:47 But on the Itsy I needed to do better, so I made processes use several pages (one for task, one for headers, one for definitions) and made the system able to grow to new pages for headers and definitions transparently. 04:53:00 I don't know exactly what will prove best. Maybe 4k? 04:53:12 But right now I'm wanting to stress that code, so I've got it small. 04:53:16 It will run with 512 byte pages. 04:53:16 Anything above 10 MB is just unimaginable, unless it's something like sound/audio/video. 04:53:24 But not 256 - not enough room for the stacks in the task block. 04:53:39 That's right. 04:54:25 How did previous programmers do floating point on an 8-bit chip? 04:54:45 That treated floating point numbers as a small data structure. 04:54:51 And just ground through the operations. 04:55:08 Oh. Fortunately I'm looking at some ROM alls 04:55:09 calls* 04:55:15 You've got a multi-byte mantissa, a (possibly) multi-byte exponent. 04:55:36 On a calculator I bet they do it in decimal (scientific notation) directly. 04:55:49 These the gory details 04:55:50 The FPU uses mantissa*2^exponent 04:55:50 http://tutorials.eeems.ca/ASMin28Days/lesson/day18.html 04:56:06 Which is slightly more accurage - see this "classic" article: 04:56:30 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 04:56:35 I'm fortunate to have that amazing tutorial at hand, everything I know about Z80 assembly is from that guide 04:57:00 Ah I've seen that article linked before, but haven't read it. 04:57:05 It's a good one. 04:57:23 There's really no rocket science involved with floating point. 04:57:41 But nonetheless you can bend yourself over a hundred different ways when you're writing code. :-) 04:57:42 I see. 04:58:09 Floating point errors suck, that's for sure. 04:58:20 Yes for sure. 04:58:26 Makes them unpredictable for some calculations 04:58:34 I did a good bit of numerical programming back when I worked for the University of Texas. 04:58:48 Oof, I can't imagine. 04:58:52 Modelling electromagnetic fields in rotating machinery, primarily. 04:59:04 It's one of those areas that laypeople take for granted 04:59:05 We built railguns and stuff. 04:59:14 And rotating machinery to power them. 04:59:24 So like motors and generators, except for transient "pulsed" operation. 04:59:27 Did you use Forth? ;) 04:59:34 :-) No, not back then. 04:59:40 FORTRAN, primarily. 04:59:48 I'm old. 04:59:56 Ah. Never used it. 05:00:08 Well, it's pretty lame by modern standards. 05:00:18 But it was one of the "first ones," so it was amazing at the time. 05:00:40 I think the only reason anyone cares about it anymore is because there's a shit ton of legacy source code out there. 05:01:13 What are some examples of large projects written with Forth? 05:01:27 In the early days at UT I wrote my FORTRAN programs on punched cards. :-) 05:01:42 Oof, I'd imagine a misplaced hole meant bad news? 05:01:59 Others here will be able to answer that one better than I can. 05:02:21 I don't really stay caught up with Forth "state of the art." I mostly just work on my own. 05:02:26 My own Forth, that is. 05:02:28 What are some limitations of Forth? 05:02:37 Run time type handling. 05:02:41 Right, you can go a long way with your own implementation. 05:02:43 You could implement it, of course. 05:02:44 Ah, evidently. 05:02:56 Everything is an unsigned integer 05:03:06 Ine one sense Forth has no limitations - it's Turing complete and it doesn't forbid you from doing anything. 05:03:10 So you can write anything in it. 05:03:27 Same with assembly, but we write Forth for good reason 05:03:39 Right - Forth has a much better abstraction capability. 05:03:52 While still being fast! 05:04:00 So your real question is what are the things that are typically not provided in a powerful way in existing Forth systems. 05:04:05 String handling is generally poor. 05:04:16 No help with structures - you're on your own. 05:04:25 No dynamic memory management - you're on your own. 05:04:45 No automatic conversions (casting). You're on your own. 05:05:02 It would be nice to write "hello " + "there" in a language 05:05:22 When you target an application in Forth, you're expected to add all things like that that are necessary to provide the user a "nice language" for the application. 05:05:26 So Forth is not for the uninitiated. 05:05:37 No, I don't think so. 05:05:38 Right. Thinking Forth calls these "lexicons" 05:05:49 Writing really smooth Forth is a good bit of work. 05:05:50 Wouldn't it be harder for new programmers? 05:05:56 You need to THINK about your problem. 05:06:00 Right. 05:06:09 Well, I think in some sense Forth would be a great introduction to programming. 05:06:18 I was/is total noob in Forth 05:06:19 When done well, it captures the core essence totally, I think. 05:06:27 and Forth is very good for uninitiated 05:06:38 My very first programming experience ever was programming my HP-41CV calculator in college. 05:06:41 I was also a noob a couple of months ago 05:06:42 because it is simpliest form of programming 05:06:44 It's an RPN / stack based calculator. 05:06:56 So I got "stack think" in my head right from the beginning. 05:07:10 And the stack only had four elements (well, it also had a "LASTX" register). So 4.5. 05:07:17 So you get really good at stack efficiency. 05:07:42 I've used the Emacs calculator which is also stack based 05:07:49 A calculator in Forth would be cool 05:07:54 One thing you could do there that you can't do (normally) in Forth is "roll up" which brought the bottom element of the stack into X. 05:08:05 Sort of like ROT, only with 4. 05:08:23 So Forth asks you to regard the stack in a slightly different way, but for the most part that skill was portable to Forth. 05:08:31 I was GOOD at programming that thing. 05:08:57 Yeah, a calculator lexicon will be on my agenda at some point. 05:08:57 I think ! and @ are excellent notations for setting and de-referencing a pointer, by the way 05:09:12 C's * and & madness is confusing 05:09:17 Well, me too, but I've used Forth for so long that I suppose I'm tainted. :-) 05:09:47 Here's another place where my informral background comes into play. 05:09:53 I don't think in terms of "de-referencing." 05:10:00 I have an address - I can fetch and store using it. 05:10:04 Right 05:10:07 I really picture the underlying hardware. 05:10:32 So you didn't study computer science in university? 05:10:53 No, electrical engineering with the computer block specialty. 05:11:03 I had to take maybe two CS courses. 05:11:15 I did take a formal class in data structures. 05:11:21 Ah, a different world. I'd imagine EE is all about efficiency and performance right? 05:11:40 Yes. Speed, power consumption, reliability, etc. 05:11:55 And my "hands on years" were before FPGAs. 05:12:17 We had their grandparents, PALS and other types of PLDs (programmable logic device). 05:12:25 But they were very, VERY simple by modern standards. 05:12:40 I did a lot of work using the standard 7400 logic devices. 05:12:54 Quad gates in a package, registers, counters, etc. 05:12:59 The field of CS is so large, there's everything from very theoretical to very practical 05:13:08 yes. 05:13:20 I quite admire formal CS - I think that's excellent knowledge to have. 05:13:39 I think of myself as "knowing enough to be dangerous." 05:13:52 In CS, that is. 05:14:32 They complement each other. Performance is moot if you can't guarantee correctness etc. etc. 05:14:37 I think I like Forth because it has that very pragmatic, non-theoretical approach woven into it. 05:14:48 Very easy for an EE with just a smidge of CS to understand. 05:15:00 A language with no formal grammar as well! 05:15:07 It's very clear how it maps onto the processor's hardware resources. 05:15:27 Right. 05:15:43 Well, except for ({.*}{:space:}*)* (sorry if my regex is a bit off) 05:15:54 I grok formal grammars at the concept level - I know about state machines, so it makes all the sense in the world to think about how some input streams will run the state machine to the right places and others won't. 05:16:09 But the formal language for discussing such things isn't in my toolkit. 05:16:22 I did have to draw a couple of state machines in planning my system--- INTERPRET is a mini state machine 05:16:35 Yes. 05:16:36 Or the WORD <--> GET_STRING cycle 05:16:46 And EXPECT and QUERY, since you have to process the cursor controls. 05:16:53 WORD calls GET_STRING if there's no more input, etc. 05:17:06 Ah, that's not quite how I did it. 05:17:17 My strings are null-terminated, and null gets parsed as a word. 05:17:27 It's an immediate word, that pops you out of the INTERPRET loop. 05:17:33 So you're back in QUIT, and QUIT runs QUERY. 05:17:57 NULL gets EXECUTEd, and does a multi-level return. 05:18:17 It's a cleaner structure. 05:18:30 One thing I don't like about some languages is their obsession with terminology, for instance, Haskell. 05:18:40 But at some point I suppose you have to name things 05:18:53 I agree - I'm not well-educated on that terminology, so it becomes a barrier to learning for me. 05:19:07 Forth is supremely easy to learn, because basically there are no rules. 05:19:16 Or perhaps there's just one rule, or 1.5. 05:19:29 To give some examples from #haskell functor, applicative, monoid, arrow etc. etc. 05:19:33 Forth was a good relief from that 05:19:37 :-) 05:19:54 See, this is how I felt about closure. I didn't really understand what you guys were saying. 05:20:01 But I sensed you were saying something really simple. 05:20:07 Well there are non-obvious names like NIP TUCK OVER etc. 05:20:09 Just closed to me because of terminology. 05:20:14 Yes, for sure. 05:20:19 Closures are words with their own frames, basically. 05:20:22 But in Forth you know going in that the name is just a label. 05:20:27 So of course you have to learn those labels. 05:20:36 Oh I especially love the SEE word 05:20:42 Imagine writing an equivalent in C 05:21:00 I have a pattern in some of my names - for example, when I make a word that is some other word but has . prepended to the name, that always means it retains one stack item that the word itself would drop. 05:21:05 .@ keeps the address on the stack. 05:21:08 Etc. 05:21:22 I first interpreted the definition of SEE then typed SEE SEE to decompile it and integrate it as a built-in word 05:21:25 But that's just because I honored that naming convention - it's not like the system sees the . and knows what to do with it. 05:21:28 Very meta 05:21:43 Ah that's a good naming convention. 05:22:03 I found myself writing things like DUP 0= a lot. 05:22:10 So that can be replaced with .0= 05:22:25 Not only do I avoid the extra word DUP, but .0= is a more efficient primitive than 0= is. 05:22:40 Well, I'm not sure if that one is. 05:22:45 But .= is more efficient than =. 05:22:54 Because it doesn't have to change the stack pointer. 05:23:22 .>= and .< become super handy for checking a data item against a series of ranges. 05:23:32 You want to get rid of the range boundary, but you want to keep the data item. 05:24:07 I have conditional return versions of those too. 05:24:15 So a range check for me is typically like this: 05:24:35 I wrote a word called T. that prints the top of the stack 05:24:57 : ?range1 .<; .>=; ...handle it... ;; 05:25:03 Note the double return at the end. 05:25:10 If I've found the right range, I don't want to check the rest. 05:25:14 Then I have 05:25:31 : ?range1 ?range2 ?range3 ERR ; 05:26:04 So if none of the ranges claim it, I can treat it as an error. 05:26:08 Right. 05:26:17 That's a good idea. 05:26:25 I've found that the . words, the conditional returns, and the multi-level returns have tremendously shortened my code. 05:26:30 They're valuable. 05:26:42 But what to name them? 05:27:12 [optional .]; 05:27:16 or ;; 05:27:22 A version of IF that keeps the result of the test is apparently called "anaphoric if", or AIF 05:27:37 I have ; ;, ;; ;;, and n; 05:27:42 n; takes a parameter. 05:27:43 So instead of doing BEGIN KEY DUP 5 <> WHILE . CR REPEAT you write 05:27:50 Returns that many levels (0 is a normal single return). 05:28:13 I'd do that like this: 05:28:31 : key .5=; . cr me ; 05:28:48 Oh, sorry. 05:28:57 : key 5 .=; . cr me ; 05:29:01 Ah I should experiment with other special forms, currently it's only numbers or words 05:29:21 But what about other forms like radix: 16#BEEF 2#010010 05:29:46 16:beef 2:010010 05:29:55 Or, for those specific two, I'd allow 05:30:00 x:beef b:010010 05:30:10 It would be interesting to explore non-determinism + backtracking in Forth. 05:30:14 The design is for :. 05:30:21 I allow the x: and b: as special cases. 05:30:47 For outputting those I support C-like format strings. 05:31:11 17 s" %x" type would print 11 05:31:16 Huh I see. 05:31:44 Implementing that was fun - I use a stack frame, and one of the cells of that frame I treat as a "meta stack" with one-byte entries. 05:31:57 What about an idea like: q{ 1 2 3 } q{ 4 5 6 } q+ 5 q= to find the first pair of numbers that add to five? 05:32:00 I sort of "execute" the format string, and digits appearing in it accumulate on that stack. 05:32:08 a . will push a fresh zero to that stack. 05:32:09 It would definitely not be very forthy, adding strange control structures 05:32:17 Ah I see. 05:32:33 So s" %12.4f" will give me 12 and 4 on the meta stack, and when f "executes" it uses those to do its formatting. 05:33:02 I've thought about abstracting stacks, but it's hard to do it without much overhead 05:33:12 I can have a string with several such fields in it - each one takes yet another stack parameter for its output. 05:33:21 By that I mean you could make a word with its own stack as its state for instance, like your frames I suppose. 05:33:27 Then when I'm done with the whole string the frame is cleared and the printed arguments are popped. 05:33:45 Well, that meta stack lives in one cell, and can only support 8 bit numbers. 05:33:51 But that's enough for format strings. 05:34:12 What papers are written about Forth? 05:34:22 I've found this: https://arxiv.org/pdf/1605.06640.pdf but I don't understand any of it. 05:34:30 There's a really good one I haven't been able to find lately about word frequencies in Forth code. 05:34:37 Interesting idea though, generate Forth programs instead of writing them. 05:34:37 I need to chase that one down and archive it. 05:35:16 The GForth guys wrote a study of various optimizations involving caching stack items in registers. 05:35:27 Short answer there is that caching the TOS in a register is pretty much always a win. 05:35:35 That's what my one does. 05:35:37 Caching more might be, depending on the processor. 05:35:46 yeah, I consider that an automatic thing. 05:35:52 I wouldn't write one without doing that. 05:36:10 Keeping more in registers can help significantly if you make your compiler smart enough to re-arrange that mapping. 05:36:14 Makes stuff like ( a b -- b ) a single instruction "pop hl" because BC stores the TOS 05:36:30 For example, if you cache two, then SWAP can just become a compile-time relabeling instead of any actual run-time code. 05:36:35 But that's pretty involved to support. 05:36:43 Interesting idea. 05:36:52 Requires multiple versions of a lot of primitives, and the compiler chooses which one to compile / execute. 05:37:04 But stack elements are small enough for most things to just use a sequence of push/pops 05:37:16 A smart Forth compiler. 05:37:16 It's similar to the type stuff we were talking about earlier - the current register mapping becomes a search criterion. 05:37:38 That's one interesting application of Forth, creating a chain of trust to a C compiler. 05:37:46 I've mentally toyed with that idea to some extent, but just decided the complexity wasn't worth it. 05:37:57 After all, 99% of the code we write isn't performance critical. 05:38:00 You write a small interpreter in assembly, bootstrap in Forth, then compile a C compiler 05:38:06 And where something is, we can use assembly. 05:38:18 Sure - totally doable. 05:38:24 Then compile Linux... 05:38:25 What are some things that are really performance critical? 05:38:33 Then compile all the languages! 05:38:35 That depends totally on the application. 05:38:39 Innermost loops. 05:38:49 I/O ? 05:38:54 Depends. 05:38:59 There's also the hardware level 05:38:59 Keyboard? Not so much. 05:39:05 SSD? Much more important. 05:39:15 At CERN they have to producess terabytes per second 05:39:20 process* 05:39:25 Or something like that 05:39:31 Anything where you the human are the bottleneck sort of automatically is not performance critical. 05:39:31 Of data 05:39:40 That's why I'm willing to snapshot my entire process for error recovery. 05:39:43 Right. 05:40:28 Well, I got to get ready for work and get in there. This has been a lot of fun this morning - thanks for the conversation. 05:40:33 KipIngram: Have you seen this talk? I think you would like it: https://www.youtube.com/watch?v=lKXe3HUG2l4 05:40:39 Thanks too, that was fun. 05:40:45 I will check that out when I get to my desk. 05:40:47 Catch you later. 05:41:04 --- quit: ncv (Ping timeout: 252 seconds) 05:42:32 --- join: ncv (~neceve@2a02:c7d:c5c9:a900:1ec6:932f:1b02:d27e) joined #forth 05:42:32 --- quit: ncv (Changing host) 05:42:32 --- join: ncv (~neceve@unaffiliated/neceve) joined #forth 05:45:39 --- join: dddddd (~dddddd@unaffiliated/dddddd) joined #forth 05:46:08 --- quit: ncv (Remote host closed the connection) 05:46:30 --- join: ncv (~neceve@2a02:c7d:c5c9:a900:6eaf:6ef7:3b81:d5f6) joined #forth 05:46:30 --- quit: ncv (Changing host) 05:46:30 --- join: ncv (~neceve@unaffiliated/neceve) joined #forth 06:47:17 --- join: rdrop-exit (~markwilli@112.201.162.180) joined #forth 06:58:22 siraben: Liking that video a lot already. 07:07:56 --- join: pierpal (~pierpal@host168-226-dynamic.104-80-r.retail.telecomitalia.it) joined #forth 07:18:27 --- quit: tabemann (Ping timeout: 260 seconds) 07:31:10 --- quit: rdrop-exit (Quit: rdrop-exit) 07:33:11 --- quit: jedb (Ping timeout: 268 seconds) 07:37:11 --- join: kumool (~kumool@adsl-64-237-235-198.prtc.net) joined #forth 07:45:05 --- join: jedb (~jedb@199.66.90.209) joined #forth 07:47:03 got this on internetz ) http://jeapostrophe.github.io/2013-05-20-forth-post.html 07:49:30 --- quit: jedb (Ping timeout: 252 seconds) 07:52:52 --- join: jedb (~jedb@199.66.90.113) joined #forth 07:59:31 --- quit: siraben (Remote host closed the connection) 08:00:06 --- join: siraben (~user@unaffiliated/siraben) joined #forth 08:38:10 --- quit: kumool (Quit: Leaving) 09:41:39 --- quit: reepca (Read error: Connection reset by peer) 09:42:23 --- join: reepca (~user@208.89.170.250) joined #forth 09:49:33 --- quit: ncv (Remote host closed the connection) 10:06:21 --- join: dys (~dys@tmo-102-9.customers.d1-online.com) joined #forth 11:09:13 --- quit: john_metcalf (Quit: http://corewar.co.uk) 13:13:21 --- quit: reepca (Read error: Connection reset by peer) 13:33:44 --- quit: dys (Ping timeout: 245 seconds) 14:23:06 --- quit: dave0 (Ping timeout: 252 seconds) 14:23:29 --- join: dave0 (~dave@90.20.215.218.dyn.iprimus.net.au) joined #forth 15:07:37 --- join: [1]MrMobius (~default@c-73-134-82-217.hsd1.va.comcast.net) joined #forth 15:11:02 --- quit: MrMobius (Ping timeout: 272 seconds) 15:11:02 --- nick: [1]MrMobius -> MrMobius 15:13:29 --- quit: nighty- (Quit: Disappears in a puff of smoke) 15:18:15 --- join: kumool (~kumool@adsl-64-237-235-198.prtc.net) joined #forth 15:31:39 --- join: wa5qjh (~quassel@175.158.225.198) joined #forth 15:31:40 --- quit: wa5qjh (Changing host) 15:31:40 --- join: wa5qjh (~quassel@freebsd/user/wa5qjh) joined #forth 16:36:25 --- quit: siraben (Ping timeout: 240 seconds) 17:05:10 --- nick: nonlinear -> NB0X-Matt-CA 17:05:11 --- quit: kumool (Quit: Leaving) 17:05:39 --- join: [1]MrMobius (~default@c-73-134-82-217.hsd1.va.comcast.net) joined #forth 17:08:17 --- join: nighty- (~nighty@kyotolabs.asahinet.com) joined #forth 17:08:39 --- quit: MrMobius (Ping timeout: 252 seconds) 17:08:39 --- nick: [1]MrMobius -> MrMobius 17:36:56 --- join: tabemann (~tabemann@cpe-24-209-155-210.wi.res.rr.com) joined #forth 17:46:21 --- quit: Keshl (Quit: Konversation terminated!) 17:52:49 --- join: Keshl (~Purple@24.115.185.149.res-cmts.gld.ptd.net) joined #forth 18:00:24 --- quit: pierpal (Remote host closed the connection) 18:05:18 --- quit: tabemann (Ping timeout: 252 seconds) 18:21:09 --- join: tabemann (~tabemann@132-83-181-166.mobile.uscc.net) joined #forth 18:23:11 --- quit: Zarutian (Ping timeout: 252 seconds) 18:59:07 --- join: dave9 (~dave@90.20.215.218.dyn.iprimus.net.au) joined #forth 18:59:49 hi 19:46:48 --- join: reepca (~user@208.89.170.250) joined #forth 19:52:49 --- quit: reepca (Read error: Connection reset by peer) 19:57:15 --- quit: tabemann (Ping timeout: 252 seconds) 20:13:49 --- join: pierpal (~pierpal@host168-226-dynamic.104-80-r.retail.telecomitalia.it) joined #forth 20:21:26 --- quit: pierpal (Quit: Poof) 20:21:37 --- join: tabemann (~tabemann@2602:30a:c0d3:1890:b90b:3bee:a83b:ed44) joined #forth 20:21:42 --- join: pierpal (~pierpal@host168-226-dynamic.104-80-r.retail.telecomitalia.it) joined #forth 20:53:11 --- join: reepca (~user@208.89.170.250) joined #forth 21:05:08 --- join: Zarutian (~zarutian@173-133-17-89.fiber.hringdu.is) joined #forth 21:31:07 --- quit: dave9 (Quit: dave's not here) 21:41:43 --- quit: NB0X-Matt-CA (Ping timeout: 268 seconds) 21:47:08 --- quit: Keshl (Read error: Connection reset by peer) 21:47:22 --- join: Keshl (~Purple@24.115.185.149.res-cmts.gld.ptd.net) joined #forth 21:47:39 --- quit: nighty- (Excess Flood) 21:48:12 --- join: nighty- (~nighty@kyotolabs.asahinet.com) joined #forth 21:54:39 --- join: NB0X-Matt-CA (~nonlinear@unaffiliated/discrttm) joined #forth 21:55:34 --- quit: nighty- (Max SendQ exceeded) 22:00:21 --- join: nonlinear (~nonlinear@unaffiliated/discrttm) joined #forth 22:02:06 --- quit: NB0X-Matt-CA (Read error: Connection reset by peer) 22:02:19 --- nick: nonlinear -> NB0X-Matt-CA 22:03:48 --- quit: NB0X-Matt-CA (Client Quit) 22:11:01 --- join: nonlinear (~nonlinear@unaffiliated/discrttm) joined #forth 22:11:35 --- quit: reepca (Read error: Connection reset by peer) 22:12:29 --- join: nighty- (~nighty@kyotolabs.asahinet.com) joined #forth 22:20:28 --- nick: nonlinear -> NB0X-Matt-CA 22:34:05 --- quit: dddddd (Remote host closed the connection) 23:59:59 --- log: ended forth/18.10.02