Transcript
Transcript prepared by
Adám Brudzewsky, Bob Therriault, Igor Kim and Sanjay Cherian
00:00:00 [John Earnest]
I really want to stress that I don't believe that there's a difference between programmers and creative people. I don't think there's a difference between art and engineering. And I think that more voices from more diverse areas of interest will always be enriching this community. So if you don't think of yourself as a visual artist, please don't use that as a reason to overlook a Decker and not give it a try. There's room for everybody.
00:00:34 [Conor Hoekstra]
Welcome to episode 96 of ArrayCast . I'm your host, Conor. And today with us, we have three panelists as well as a returning guest. We will get to introducing him in a couple seconds. But first, we're going to do brief introductions. We'll start with Bob, then go to Marshall and finish with Adám.
00:00:49 [Bob Therriault]
I'm Bob Therriault. I am a J enthusiast and happy new year, everybody, even though it's now, what, four days into the new year by the time or two days into the new year by the time this airs. I've lost track. Anyway, hopefully a good year.
00:01:01 [Adám Brudzewsky]
I'm Adám Brudzewsky. I work with way fewer array languages, specifically one, APL. That's what I do.
00:01:07 [Marshall Lochbaum]
I'm Marshall Lochbaum. I've worked with many array languages. I'm the designer of BQN.
00:01:12 [CH]
And as mentioned before, my name is Conor, array language enthusiast, massive fan of all the array languages. Happy New Year. And I don't think we have any announcements today. So we are going to hop straight into introducing our guest who you just heard, I believe in episode 95, we introduced them, John Earnest. I was actually looking at the APL wiki of the ArrayCast episode lists [01]. And I think in your introduction last episode, I mentioned you were a two-time guest of episode 41 and 43, where you talked about the versions of k, Lil, Decker, and Ok. But then I was just looking, I'm not sure how I missed this. You were also on episode 53, not as a guest, but in the featured guest column, but it says guest panelist. So I missed that episode 53. I don't even, it says the title of the episode was "hat is the problem? Apparently I brought a problem to the podcast and then we talked about how to solve it in different array languages. Anyways, I'm not sure. So I guess this is your fifth appearance. You've been a three-time guest, a one-time guest panelist. I guess, what is, I don't know what the difference between a guest and guest panelist. Have we ever, have we talked about this on the show? I'm not sure, John, if you want to weigh in today, you're a guest, I'm a guest panelist. What makes the difference of a guest versus guest panelist?
00:02:34 [JE]
Well, it's very important for filing your taxes.
00:02:40 [CH]
Okay. Well, I haven't done any taxes with respect to ArrayCast , so you're going to have to give me some tips afterwards.
00:02:42 [ML]
You shouldn't reveal these things, Conor.
00:02:43 [CH]
Sorry?
00:02:44 [ML]
Don't let the tax authorities know that.
00:02:51 [CH]
Uh-oh. Well, I mean, you know, they'll come after me if they need to.
00:02:54 [BT]
And in cases of panelists, guest panelists, guest panelists, head panelists, lead panelists, guest host, I always defer to Marshall. He is the regulator of such hierarchies.
00:03:02 [ML]
Someday we'll have a guest bouncer.
00:03:11 [BT]
We don't need one as long as we've got you.
00:03:13 [CH]
All right. Well, I think today the topic is, is we're going to get some updates on Lil Decker. I mean, we'll throw it straight over to John, because I think you're bringing the topics that we're going to be chatting about. So I guess I'm throwing it over to you, and you launch us off.
00:03:27 [JE]
Sure. Well, quite a lot has happened since Decker was originally released. Just for like brief background, if anybody hasn't watched the previous episodes, Decker is a multimedia sketchpad computing environment. It's a little bit like an IDE. It's a little bit like a paint program. And a lot of people say that it reminds them a lot of HyperCard. You can use it to make toys and games or useful applications. Quite a few people use it for building interactive fiction and visual novels and things of that nature. And the reason that I'm talking about it on this podcast is that the scripting language that's available in Decker, which is called Lil, is a direct descendant of q. It is a programming language that sort of makes itself appear like a more conventional imperative language, but it's secretly a functional language, but it's secretly an array language. And it allows people to kind of ease themselves into programming with this paradigm. So the last time we talked about Decker, it had been very recently released, and there was a little bit of buzz around it. And now we've got a bit over two years of people actively using it and building things with it, and I've been continuously improving the system as it goes along. Lil, the language, has evolved quite a bit in sort of generalizations of things, corrected the semantics of some stuff, added some nice features. A lot of the things that I find most interesting about it sort of center around its query language, which is a little bit like qSQL, but more general. And also some interesting sidetracks, like the fact that I wrote an implementation of Lil in awk, so that it's runnable on literally any POSIX environment, even if you don't have access to a C compiler. And Decker has evolved in some pretty dramatic ways as well. There's a new mechanism for user-defined interactive components, there's improved color support, and I added a system that lets you sort of break out of the usual sandbox of Decker. The facility is called the Danger Zone. And of course, there have been many, many fantastic things that people have built with Decker, and lots and lots of minor features along the way. So that's sort of a sample platter. What would you guys like to talk about?
00:06:17 [CH]
Well, first of all, you've built... I mean, you mentioned it, but we're definitely going to immediately circle right back to it. I'm already searching on GitHub, but I haven't found it in the time that you were chatting. You wrote an implementation of Lil in awk. Is this available on the interwebs so that I can look at it? That seems wild.
00:06:35 [JE]
Yeah, if you go to the Decker repository on GitHub, if you go inside the tools directory and source under awk, there's Lila. And there's also a post on my blog on beyondloom.com that's about... the name is Lila.
00:06:55 [CH]
2002, 1381 lines folks, that is uh wow.
00:07:01 [JE]
It's a pretty substantial awk program. So I guess for the uninitiated, awk is a very pleasant scripting language that is probably the most general purpose scripting language that's part of the POSIX standard. On any Nix, any BSD, and increasingly on Windows, you'll have access to some form of awk. There's even an awk in BusyBox. It's mainly intended for doing sort of columnar text processing and has a lot of features that are geared towards that. But it has floating point arithmetic. It has associative arrays. It has the normal collection of control flow structures. So it's significantly better than just Turing complete. And so it turns out that you can build up... I can build up something that's compatible with Lil's normal internal virtual machine on top of that substrate. And then the only reason that it's as long as it is, is because it's not just the interpreter, but it's also a hefty chunk of Lil's standard library as well. Things like the array interface for manipulating binary data or the image interface that can do image manipulation operations. Things that are kind of bread and butter when you're doing practical scripting with Lil.
00:08:27 [CH]
This is insane. This is very impressive. I would have never thought... I mean, it's a general purpose programming language, I guess, so you can do whatever you want in it. But I've never heard of anyone using it as an implementation language for an interpreter. It's typically a command line. It goes next to sed and stuff like that.
00:08:54 [JE]
Yeah. Well, I mean, it's definitely... I mean, I believe sed is also Turing complete in a somewhat more strained sense. But, I mean, awk is truly general purpose. You've got facilities for reading files and shelling out commands. I was originally thinking about this from the perspective of just a kind of a portability thing, trying to expand the range of platforms that you could use this language on more easily. And I initially had extremely low expectations in terms of the kind of performance I would be able to get out of implementing an interpreter in bash or awk. I originally wanted to target bash, but when I took a survey of all of the computers that I have available, some of them have quite old versions of bash that had very, very limited support for associative arrays even. So I would have had to do everything with string manipulation. And bash doesn't intrinsically have support for floating point numbers, which would have been another huge, huge pain point. I could have shelled out to DC and BC to do that from bash. There have been a few program generation approaches that tackle it that way. But BC and DC are not anywhere close to as omnipresent as awk. But if I was writing it mostly in bash, but shelling out to awk, it seemed very silly because awk is a much nicer programming language than bash. So I just wrote the whole thing in pure awk. There are a few little fiddly bits that it has to shell out to something external, but there's basically no core functionality that does that. It's just one awk process. It's kind of terrifying how fast the end result is. It's quite usable in some of the humblest machines in my arsenal.
00:10:55 [CH]
It's a very impressive piece of work just from glancing at it. So I mean, we'll make sure to put the link to this exact file, Lila.awk, if folks want to take a look at this and be inspired. I mean, what language was, or actually, different question. How many languages has Lil been implemented, including awk?
00:11:14 [JE]
Well, there's three implementations of Lil that I maintain. There's the C implementation, the JavaScript implementation, and the awk implementation. I built the JavaScript one first because it was sort of a more pliable material than C, and then I rewrote it in C, and now I maintain them in lockstep. I find that that's not very much more difficult than transpiling one implementation to multiple platforms. Occasionally, I make a little consistency mistake, but I have pretty good test coverage for the Lil interpreter, and it isn't really that much of a problem. I've actually found that maintaining implementations in a couple of different source languages, it forces me to rethink every piece of code at least once, and sometimes just in the process of transliterating it, I get an idea for simplifying something, or I realize that I missed an edge case or something like that. It's not an approach that I would recommend for all projects, but it does work pretty well for me. And by using...
00:12:31 [ML]
Yeah, well, you have to have a pretty solid idea of what the programming language is supposed to be about, right?
00:12:36 [CH]
Oh, certainly.
00:12:37 [JE]
Well, and that's why I wrote one entire implementation before I started this multi... Because it would have been an enormous amount of unnecessary overhead if I had just been churning on every early change to the design. But now that Lil is relatively mature, and I'm not making sweeping, breaking changes very often, it actually provides a nice amount of back pressure. I have to think about the fact that, "Well, I'll have to do this in the awk version too." I have to.
00:13:07 [CH]
How many... Because I know that BQN also has BQN.js. Does Uiua also have... How many of the array languages...
00:13:14 [ML]
Uiua is just Rust, I think. [02]
00:13:16 [CH]
Is Uiua just Rust? There's no ... I guess they probably compile the WebAssembly then and run it there.
00:13:21 [ML]
Yeah, well, the whole website is based on this Rust framework. I don't remember the name, but...
00:13:26 [CH]
Right, Okay. So maybe it's just Lil and BQN then. Definitely Dyalog APL doesn't have a JavaScript implementation, I don't think. And J probably doesn't either.
00:13:38 [ML]
Yeah. Well, in BQN, not everything is actually re-implemented because the compiler is in BQN. And JavaScript doesn't implement any of the runtime. So it's just stuff like math functions I've had to... There's a in C you call libc for the gamma function for factorial. In JavaScript, there's no... JavaScript's math doesn't have that. So I just did a basic version that only works on integers, things like that. So it's not really completely redoing all functionality.
00:14:09 [CH]
Well, I mean, you mentioned the sweeping breaking changes. So maybe that's a good thing to go to next. Maybe you can give us a summary and then we can chat about some of the... Maybe not just sweeping breaking changes, but you said you also had evolved Lil a little bit and potentially... Yeah, there's stuff to chat about there.
00:14:31 [JE]
So I guess the biggest set of breaking changes that I've made have all centered around Lil's query language. So like q, Lil has a SQL-like syntax that you can use to express manipulations of tabular data. And this generalizes nicely to all of Lil's collection types because there's a pretty natural way that you can widen a list or a dictionary into a table. So it accepts any of these data types. And then you have the ability to do filtering, sorting, and grouping, and then filtering under group and sorting under group, and so on. It's kind of like a big, interesting feature to me to take a bunch of functionality that ordinarily would be built into operators or built into libraries and make it central in this query language rigid structure. It kind of takes a very wide range of interesting algorithms and then turns it into one set of modular pieces that can fit together. A lot of the breaking changes around it have been making generalizations to it in order to have a more transparent set of semantics for everything and a more modular approach to the way the clauses fit together. So like in qSQL and in ordinary SQL dialects, you have a specific order in which where, by, order by, and so on are carried out. And if the sequence of operations you want to carry out doesn't fit into that rubric, then you must use a subquery or intermediate tables or something of that nature. And in traditional SQL, you're dealing with queries that are sort of record-oriented in a formless void of tuple space that has some ordering, but you shouldn't depend on it generally. Whereas in QSQL, it's a column-oriented dialect where basically all of the column expressions that you're doing are just a regular q or k expression that's conforming columns together, manipulating them all at once, and then hammering on a permutation vector as it's dragged along. And Lil is very much the same sort of idea as qSQL, where it's a series of clauses that are each a simple, entirely general Lil expression where you can do anything, you know, call your own aggregation functions, but all of the clauses, the where, by, and order by, can be repeated in any sequence that you want. There have been a few false alleys that I've gone down in designing one thing or another. I found that I tried to be very clever in adding special cases in certain situations where it would make a more elegant formulation of some common use case, and in basically every instance, I've ultimately found that it made things more confusing and backed it out. Initially, the insert statement, which is one of the ways you can construct a table, was column-oriented like everything else in the query language, and I quickly realized that the fundamental problem with that is that it made insert just like an uglier version of select. In all situations, if you just wanted to make a new table from scratch in a columnar perspective, you could just select from any table and ignore the input tables and generate a new set of columns. So there's now a row-oriented version of insert. And there's also been a lot of things where I've just been sort of slowly accumulating wisdom from k and some other array languages. Coming up with a relatively sane approach to doing dictionary conforming is kind of a nice one, so that you can do some lazy, not lazy, but sparse collections of tabulations, and it just works. It joins across dictionaries, and you just accumulate unique keys and things like that.
00:19:23 [CH]
Is this coming from other k's and q's, this inspiration for this stuff?
00:19:30 [JE]
Yeah, so k6 and k5 leaned pretty hard on the idea of having a real algebra over the dictionary data type. In early Ks, dictionaries were a very rudimentary data type where you could index into a dictionary, you could construct a dictionary, you could tear it apart, and of course you could match an entire dictionary against another entire dictionary like any data type. But you couldn't really like some dictionaries, which made it sort of like a second class data type in a lot of ways. Whereas in k5 and k6, Arthur Whitney made it a better integrated data type with the language. A full generality of any data type can be a valid key. It gets a little bit weird if you start mixing types of keys in a dictionary, but you could do it. And making all of the primitives have some sort of a sensible interpretation over a dictionary, like the generalization of grouping producing a dictionary rather than producing a list of lists of indices, was kind of a useful step. In the oldest versions of k, there was this duel between the question mark operator, which is sometimes called distinct, the monad, and the equals operator, which is group as its monad. And the distinct would give you the distinct elements in order of appearance. Group would give you the indices of distinct elements in order of appearance. And in many cases you could then sort of zipper them together if you needed the association between things and where they appear. But if you have a dictionary data type and you're taking it seriously as a core data type of the language, then it's much more natural to have group be a single operation that produces both of these things at once. In order to calculate the k-style groups of the list, you do need to somewhere be keeping track of those distinct elements. So why throw it away and and recompute it a second time? And it also, you know, it gives you the option to then generalize a bunch of operators so they work through a dictionary. You know, you keep the the spine of the key set constant and manipulate the data elements underneath it. So like if you wanted to calculate the number of occurrences of elements in a dictionary, you group it and then you count each, push it down into those lists of indices, and now you have a dictionary mapping those same keys to number of appearances.
00:22:27 [CH]
So this is similar to the inverse indices in BQN, correct? The counter?
00:22:34 [ML]
Yeah, it is. And APL also has indices inverse. So that's like indices gives you from the number of counts it'll replicate indices that many times. I guess the difference is that BQN, it just tells you the number of each, well, of each index. In k, you can pass it anything, and it'll give you a map from whatever, from each unique value in that argument to the number of times it appears.
00:23:01 [JE]
Yeah, it's a ragged structure, which is very k-like.
00:23:04 [ML]
So basically the idea is in BQN, the output is a list. So its keys are the number 0, 1, 2, and so on. So BQN is only allowed to count those numbers. And k counts anything and gives you a dictionary out. So it's kind of more general.
00:23:17 [JE]
I think that Dyalog APL has key, which is like, it's not quite the same operation, but it's similar. Because it's sort of, I mean, Adám, you can...
00:23:30 [AB]
Yeah, but it allows you to do that thing you would do with a dictionary, right? You say you get the dictionary, and then you could do something on each one of them, whereas key takes an operand and directly does that thing on each one immediately. So you don't go by a dictionary, you go directly to the end product. Although it has potential performance problems because...
00:23:52 [ML]
Yeah, well, and it's based on J's key, but it adds a bunch of stuff. Yeah. It's very complicated. Yeah, well, in practice, it often goes via the unique elements and indices of each.
00:24:03 [JE]
Yeah, but it's a bit more rigid. But just the whole point is that, I think I touched on this a little bit in the last episode, just if you add dictionaries as a serious data type to the APL framework, then it leads you to start thinking about a lot of interesting generalizations of the existing verbs and adverbs and things.
00:24:27 [AB]
This is a reason I think we should not add dictionaries to APL. It would be the wrong move. It's a different language. You don't try to patch up things you have with a new type all of a sudden. It has to be thought of from the outset.
00:24:40 [JE]
Well, and I mean, that's why k exists as a separate language.
00:24:45 [AB]
Well, all of them.
00:24:47 [ML]
Yeah.
00:24:48 [JE]
Yeah, well, so far there's only one Lil, and I'm not really intending on making a Lil2 or a Lil5.
00:24:55 [CH]
You say that now. You say that now. [laughter] Okay , I mean, so we've been focusing on Lil, but I know also you said that there was a bunch of changes made to Decker. And I think you also mentioned on last episode that there was a, what do you call it, a Decker jam or a thing jam, the in Decker?
00:25:14 [JE]
A A thing jam or or a game jam? [03]
00:25:17 [CH]
Yeah. You want to highlight some of the projects that were done? Or I'll throw it to you and you can take this however you would like to take it. 00:25:23
Well.
00:25:24 [JE] [TODO: Sanjay's starting point]
Well, by the time that this episode comes out, the Deck-Month will have finished and I'm sure that there'll be some really fantastic submissions. So I don't want to show any favoritism and highlight specific ones _just_ yet, because things are still very much cooking. But we've had some really fantastic creations over the several years that we've been doing this so far. People have made "demakes" of games. There have been a lot of visual novels, which are kind of a specific format of interactive storytelling. Zines. One of the things that's really rewarding is how Decker is very usable if you don't write any code at all. There's kind of like layers you can build up as you take advantage of more and more of the things it can do and having more interactivity in things. Some people basically just make a magazine that you can flip through, maybe in a nonlinear structure, and then you can sort of sprinkle in fun things. One of the new features that sort of facilitates doing this is something called "contraptions". So in Decker, the organization of everything is that you have a series of cards that each can have something drawn or written on the background. Widgets are interactive elements, like a button or a slider that the user can make something happen with. There's a small collection of primitive widgets that have built-in behaviors. And a contraption is a way of bundling up a set of those as a new modular piece. From the inside, it sort of semantically looks and behaves as if it were a card with its own widgets inside of it. And from the outside, it behaves like a widget. What's really nice about this is that it makes it very, very easy to build functionality that allows beginners to take something that you've made and just incorporate it into their project. You can literally copy-and-paste a snippet of text that's the clipboard representation of a widget that might come with its contraption definition (or even fonts that it references coming along for the ride) and then paste it into a card and immediately start using it. So the more advanced users in the community can write little scripts and build complicated contraptions, bundle them up, and then a beginner can use this thing: in many cases, just create a copy of it, open up the inspector for its properties and set a couple of checkboxes or paste a couple of images into it. It will bring with it this new composable behavior. It helps provide a smooth gradient for beginners to ease themselves into making more and more complicated stuff in Decker.
00:28:48 [CH]
Yeah, I mean, we'll include [this] in the show notes for sure. I just Googled the the Deck-Month and have come across both of them. I accidentally clicked on one and then some music started booming in my headphones, [John laughs] which is why you might have seen me make a face [chuckles]. I quickly [hit] control-w. But there's a bunch of super neat [ones] and also a wide variety of different projects. Like you were saying, some people are just doing it for sketching kind of a magazine and other folks have put together much, much more involved [projects]. Quite impressive, really. And so this is not the first time you've done this, then?
00:29:29 [JE]
No, we've been trying to do jams for Decker about twice a year. We do one in December called Deck-Month, because it makes for a nice pun. And then we do Decker Fantasy Camp in the middle of summer over the course of July. We just make them month long. It's unranked. There's no specific theme and not very many rules that you have to comply with, just to make it as open and non-stressful as we can make it [chuckles].
00:30:04 [CH]
Of any of the past Deck-Months or Fantasy Camps, do you have a couple that you want to highlight that really showcase the cool things you can do? Not to pick favorites. This is not "John picking a favorite". This is "John picking one or two submissions, just to highlight the kind of things that you can do".
00:30:23 [JE]
Okay . So historically, things that I can think of, there was a really amazing creation that [is by someone with a] Polish name. I believe it is pronounced "Chee-Chee". The creator modeled this environment in plasticine and then took photos of them and incorporated them together. When all of the photos were brought in, they get Atkinson-dithered. So it's this wonderful, one-bit neverhood experience. There isn't really a specific goal. There's just kind of places you can walk around and interact with. It has a lot of really funny gags and weird things in it. It's very striking. We also had another piece that I quite liked is called Desker, created by Amwa, one of our participants in the community. It's basically just a complicated desk environment, like a representation of a desk with, little figurines and knickknacks and books on a shelf and so on. Everything is interactive with lots of little animations that you can find. You can slide open a window or fiddle with books. It's just this playground of discovering nice little interactions. And also it was one of the first really nice decks to take advantage of working with 16 colors in Decker. So it kind of blew a lot of people's minds when it first came out; they're like: "wait, you can make stuff that looks like that in Decker?" This lovely pixel art.
00:32:25 [BT]
It seems to me that something like that would be a great source for somebody who is trying to learn it because you've got the contraptions working through it. "So how does that happen?" Then you look at the contraption; you can break it up and see exactly how they've done it.
00:32:37 [JE]
Well, yeah. Another thing that's kind of unusual about Decker is [this]: normally when you're authoring decks, you'll use native Decker, an application that runs on Windows or Linux or macOS. It can produce instances of Web-Decker, which is the JavaScript and HTML version. But Web-Decker is not really a lesser version. It has all of the editing tools; it has the little REPL. When you publish projects, you can lock them, which hides the little menu bar at the top and tucks all the tools away. But it's very easy to bring them all back. Something that I have seen an increasing number of decks do over the years is start out locked so they can just sort of present themselves as a game or something. But when you get to the end, they'll unlock themselves and you can click on a button and then pick it apart and explore it. And sometimes people even have elaborate behind the scenes areas where they have leftover things that they were working on or scribbled sketches or notes; or even things that are never intended to be seen that are part of the functioning of a deck. Like if you have an adventure game, you might have a card that is never shown to the player that directly represents the player's inventory and the status flags that is used for debugging as a visual interface when you're making the game; it's still there. All of the data inside of a Decker project is sort of reified in widgets. If you want anything to be persistent, it lives somewhere physically in the deck, which is kind of a nice property.
00:34:29 [BT]
In one of the deck fantasy camps, I see there's just something labeled as a tool. I think that's something else you can create. So what's the difference between a tool and a contraption?
00:34:37 [JE]
Well, a tool is just kind of how somebody chooses to describe their whole project. You can make decks that read and write files [or] that compose music. I made a reasonably popular deck called Wiggly Paint, which is just like a weird paint program that happens to be built inside of Decker. It's all just kind of a choice of perspective on it. Because it's this plastic environment, when you're designing things, you can sort of make things that are like turnkey applications (if you're locking a deck). But also, if it doesn't matter very much for the experience, you can just leave the tools enabled. Instead of having configuration options (instead of like giving your application a dark mode or something) just let the user make those superficial changes. If they would rather have the toolbar on the left instead of the right, just switch to widgets mode and drag it around. If they don't like the palette, just change it.
00:35:50 [BT]
And with Lil, they can make substantial changes, not just cosmetic ones. There can be real functionality. They can change them in something that's been created.
00:36:02 [ML]
Well, you have as much power as the creator of the deck, right?
00:36:03 [BT]
Yeah.
00:36:06 [JE]
Exactly. And in many cases, there's just things that we think of as being a necessary part of writing application software that just is not relevant. There's no code involved in setting up a user interface in Decker: you just draw it and drag out some widgets. There's no code that you need to write to serialize your application because (even under scripted control) you can just save the current deck whenever you want. And the deck already is this data serialization mechanism. Since all of the persistent state of a program is embodied in widgets, in between every frame of executing a deck, there is a checkpoint that can be taken if you want to. And you could restore the deck to exactly how it was.
00:36:56 [BT]
Has Decker ever been used in education?
00:36:58 [JE]
So far, I have read a couple of papers about it being included in some game design programs. And I've talked to a number of educators who are interested in using it in that way. As of yet, there aren't huge developments for that but if anybody is listening to this podcast [and] they're a teacher (they want to incorporate Decker into their lesson plan) please reach out. I would love to help you.
00:37:25 [BT]
It seems to me that because it has these different aspects of a computing language, like functional or imperative, and all these things combined, [04] it seems to me that if you were trying to give somebody a sense of the interfaces between those different styles, this might be a good way to basically immerse them in it.
00:37:42 [JE]
I think so. Well, and also just easing yourself into needing to program, but also having this programming language that is generally pretty simple, but very much designed around an incremental learning experience. As you try to do more complicated things with Lil, you can take advantage of more of its sophisticated functionality. Your programs stay about as concise as they get more and more powerful. I think that incorporating ideas from APL family languages is just completely obvious when the goal is to create something that is highly expressive. Of course, the the biggest philosophical decision and what probably makes Lil less exciting to a lot of people who are excited by array languages is the choice to use tokens that are words rather than symbols. This is something that's very near and dear to all of our hearts, although it's a little bit different coming as a k programmer and being used to being shackled to an ASCII character set. I do think, of course, that the more concise notation of array languages can be very beautiful. But it is unambiguously the case that learning to type these new character sets, working with the tooling, the fonts, the keyboard layouts can be a barrier to this stuff. It's a tradeoff that isn't going to please everybody. But I hope that Lil will be powerful enough to satisfy many people and that some people will be excited by Lil and then more excited if they try J or k or APL or maybe even something else.
00:39:47 [BT]
It would be an entry drug.
00:39:49 [JE]
[laughs] Yes.
00:39:50 [CH]
So wait, to drill down on exactly what the barrier is in your opinion: you mentioned typing, but technically J and k (and I guess we'll ignore q because q is actually similar to Lil in that it uses keywords) those technically are all ASCII symbols.
00:40:15 [JE]
Yes, definitely. It's not a step function; it's a gradient, right? There's a bit more memorization. There's a bit more getting used to reading things character by character and line by line rather than skimming. There's a little bit more grippable, mnemonic value to terse names over opaque symbols, although as I've talked about in the past, you do have to memorize a few things in k and then you can read it [laughs]. It's a learnable skill and no programming language is truly intuitive. It's just some things are closer to stuff that you've seen before. Lil is designed to look like programming languages that people have seen before. It is specifically visually modeled after Lua, but semantically it's very, very similar to q. I'm kind of just tricking people into trying something that's very different from what they might be used to by putting it in an appealing wrapper.
00:41:16 [ML]
You're only tricking people if you say that q syntax necessarily goes along with q semantics. I mean, its your programming language, so of course it is a hybrid of two existing things, but does that mean it's less natural than either of those on their own (the mainstream syntax and the array semantics)? I don't necessarily think so.
00:41:37 [JE]
I mean, I think it's a pretty reasonable balancing point and some people like it. So I don't think it's been a failure [chuckles].
00:41:45 [ML]
Yeah. Something I've been thinking about is that the contraptions and widgets you talked about are really very similar to objects and fields, aren't they?
00:41:56 [JE]
I mean kind of.
00:41:57 [ML]
Because a widget is how you store state; a field of an object is in Java how you store state. You might call it a different presentation of the same underlying system or the same goals that you're trying to accomplish.
00:42:12 [JE]
I mean, they definitely have like a character to them of an abstract data type. It's not exactly object oriented but there's similar ideas there.
00:42:22 [ML]
Yeah. Well, it's kind of objects without classes for one thing.
00:42:25 [JE]
Or with exactly one layer of hierarchy in terms of a prototype and an instantiation.
00:42:30 [ML]
So you can define a type of contraption and then have multiple individual ones.
00:42:35 [JE]
Yeah. The naming convention is [that] a prototype is the design of the thing; the contraption is the instance of the design [Marshall concurs]. Definitely [laughs] wrangled with an appropriately fitting terminology for those for quite a while. But I could have called them classes and objects.
00:42:45 [ML]
So yeah, I think that that sort of speaks to the same principle in BQN that the object oriented ideas are a very good way of the larger scale structure that you put around your array oriented programs. I mean, I think the idea that the state goes into widgets (that you're very carefully controlling where mutation can happen) [is] another important idea. You only want to have mutation at the large scale and at the small scale, as much as possible, you want to keep the state out.
00:43:27 [JE]
Yeah. So all of the primitive operators and primitive data types in Lil are functional. You write most of your programs without any side effects, except for stashing stuff in Decker's object model _explicitly_.
00:43:46 [ML]
Yeah so actually it's a really cool step to say that not only does the stateful computation have to be explicit, it also has to be visual. Like you have to have somewhere in the deck that you can go and see that state. [John agrees]. So yeah, that's an interesting presentation of that idea for organization.
00:44:03 [JE]
Yeah and it allows you to sort of spatially reason about things in a way that I find very different [from] a traditional debugger or a Smalltalk image or something like that, [05] where you have hierarchy and a lot of facilities for gaining visibility into things. But it's sort of like mentally, it's a hierarchy or it's a soup. It's not like a building with rooms.
00:44:33 [ML]
Well, I mean, the whole goal is to make it as easy as possible to have objects interacting and state. So the goal is instead of to keep your code from becoming spaghetti, to make spaghetti work as well as possible.
00:44:49 [JE]
To make ravioli [others laugh].
00:44:52 [ML]
Maybe. Yeah.
00:44:52 [JE]
You want to encapsulate it in modular pieces that you can move from place to place.
00:44:57 [ML]
Yeah. So to have some fractal spaghetti where [John bursts out laughing] you zoom in and there's more spaghetti, but the spaghetti in a given region is fairly localized. [John concurs] But the idea that everything is an object. Well, do you really want everything to be an object? Maybe if your objects are good enough to accommodate a functional style, but maybe instead you want to say: "well, no, only use objects when you really need to". And that's when you have state that needs to hang around.
00:45:26 [JE]
Yeah. And I mean, from that perspective, it's just that the parts of Decker and Lil that are mutable and stateful are a little bit object oriented and the rest of it is highly functional. Your computation is functional. Your state is reified.
00:45:48 [ML]
Yeah.
00:45:49 [BT]
And from like a pedagogical or like a learning aspect of it, you start out with being able to do drag-and-drop. So you've already done some really simple manipulations and then you think: "I'd like to do a little more". You've got a motivation to learn something more and it just pulls you into it that way. I think that's really powerful.
00:46:09 [JE]
And you never have to give up the drag and drop. I wrote a blog post recently that was examining a couple of different ways that you could approach writing a game like BreakOut in Decker. And it sort of starts from: you create a canvas widget that you can do your drawing on, and you write a big blob of synchronous code that just takes over Decker, watches mouse input [and] handles all the physics and repainting. Which would be kind of a traditional "I want to just implement a video game".
00:46:41 [ML]
Well, it was actually translated from JavaScript, right? Somebody else's article.
00:46:45 [JE]
Well, the original game that I'm describing there. But I take it along through a couple of steps where I'm sort of taking advantage of more and more of Decker's capabilities. At the end of the article, I have taken the idea of BreakOut and turned it into a set of contraptions that each have their own behaviors in them. Now I have this elastic toolkit that I can use to make games that are like BreakOut. I have a generic brick. I have a generic ball, a generic paddle, and I can make multiple instances of them. I can add behaviors with the hooks that I've exposed; the events that they emit. And so you go from pure coder to having this drag and drop environment. You can keep going back and forth. Everything that you can make tangible and directly manipulable, you do. And then you don't have to write as much code. The end result sort of modularized, contraptionized approach is less code than I started with. And it's much more flexible. Most of the places that the original hardcodes constants, they become like the physical place where I plop down an instance of a contraption or the size that I drag the contraption out to. There's only just a handful of things like the ball velocity that still have to be instantiated in a more concrete way inside literally a field that lives inside of the ball.
00:48:26 [ML]
So I guess the possible downside to that is that if you've got everything [as] its own object on the screen, you can't as easily encode relations between different objects. Maybe this is possible but if you want to have two objects that are both in the same row sort of, and they meet in the middle. And you want to drag back and forth and just change the length of one and restrict [the other] so that the total length is the same. Or maybe you put another object halfway in the middle of one. If you're not writing out all the computations in terms of length, it's a little harder to express that.
00:49:09 [JE]
Yeah. Well, I understand what you're getting at. Both approaches are kind of possible. There's a continuous set of trade-offs that you can make.
00:49:20 [ML]
Yeah. Not saying that Decker's bad at this, but the one style might be less suited to it.
00:49:25 [JE]
Sure. Depending on what you're trying to do. Anytime you encapsulate something and you take a problem and carve it up into a bunch of individual components, you're making some opinionated, articulation points and that network of interdependencies. I guess the core of the design philosophy that I have here is illustrating that there are a bunch of different ways that you can approach any of those problems in the environment and different ways that you can take advantage of it. You don't have to use contraptions or an object-oriented mindset to build stuff in this. You can maintain a very shallow hierarchy and simply have your data containers sitting around on a card somewhere, still visually inspectable, but not bundled or sealed against one another.
00:50:21 [CH]
I've stumbled across this contraption bazaar because it was linked in the Desker deck, I guess, do you call it? [John agrees] And are you responsible for most of these?
00:50:35 [JE]
I've written quite a few of them because I'm the most experienced Decker programmer [chuckles], but there have been a few that have been donated by users or people have made a variation. Everything is sort of inherently open source, just as a nice natural consequence of the way things get serialized in Decker. So, of course, any contraption that anybody makes, you can just sort of remix.
00:51:01 [CH] [TODO: Sanjay's stopping point]
One of them that got used in the Desker deck was the cat's eyes would follow your mouse. That was the eye contraption. And it is pretty phenomenal that you just have this baked in. Like, if you think about how you would have to manually program that yourself, that's like a non-trivial bit of code, right?
00:51:28 [JE]
Well, in a bunch of them, these pieces, they're parameterized in various different ways. So, like the eye widget knows about a bounding box and you copy and paste any image that you've drawn in Decker into it to serve as a pupil for the eye. And then it handles the simple trigonometry of figuring out how to move the pupil around based on the position of the cursor. And, of course, you can layer things. Like, if you wanted to have a droopy eyelid on top of the eye, you could just have another canvas on top. So it becomes this process of sort of like making kinetic collages. And a lot of these components, well, they can all be customized if you write more code. And many of them expose event handlers that could do stuff in response to a user interacting with them. Many of them do useful things without writing any code.
00:52:25 [CH]
Yeah, I would encourage the listener. I mean, definitely go check out the Desker deck because it is very neat. I was clicking around and then took me to a whole other credit thing. And that's when it was like, "Oh, yeah, go check out this contraption bazaar." Because I stole or stole, borrowed a bunch of stuff from it. And yeah, it's pretty mind-boggling the stuff that you can do. Like, because you start off and it's just basically a paint program, you know, like in its simplest form. But then, like I'm staring at a chicken, like drinking from, you know, water here. It's like, "Okay, we've clearly elevated way past, you know, JS paint or the paint program that ships with Windows." Like, I wouldn't even know where to start to get that kind of thing.
00:53:10 [JE]
Well, Desker comes packaged with a huge pile of examples that range from simple to complex. And one of the advantages of Desker being this sort of live programming environment is all of the modules that I write, which are, you know, little libraries that you can insert into your decks, are packaged as a multimedia interactive documentation built inside of Desker itself. I try to make it so that all of the examples are showing the code there. And if you just make changes to it, you'll immediately see the results. Everything that I explain with words, I try to explain with interactive doohickeys. And of course, I had a couple of Easter eggs here and there to reward exploration. I think one of the examples I could point you at, I've made a bunch of decks that are all about and some topic. So like, there's all about color. It's got to be a long deck. Yeah, paste that in the chat. But it's a multimedia presentation that explains things. And as you go along, there's things that you can click and drag around. As it gets more sophisticated, there's more code. And this comes along with a module that includes a bunch of utility functions for manipulating colors, like converting between hue saturation value to red, green, blue, and parsing CSS colors.
00:54:58 [BT]
This sounds closer to Brett Victor's approaches to closing that interactive loop to be able to learn something.
00:55:06 [JE]
A bit. I don't really know what Brett Victor would think of Decker. I think he would probably be annoyed that it was constrained to a glowing rectangle. But sometimes rectangles are good.
00:55:16 [BT]
Yeah, there have to be constraints. I guess the other thing I was wondering about, there was a really large HyperCard community. And it was really interesting, because by and large, it was people who may not have been computer programmers. And they were more looking at applications and creating things that were useful to them. Have you found--
00:55:34 [JE]
Yeah, domain experts rather than programmers.
00:55:37 [BT]
Yes.
00:55:38 [JE]
Which also, historically, has been kind of an APL thing, hasn't it?
00:55:43 [BT]
It has. Has the HyperCard community discovered Decker yet? Have you seen that crossover? Because they're still around. People still do HyperCard decks.
00:55:51 [JE]
Well, so far, there have been some people from the HyperCard community that embrace it. And there are some people that just find it too different. Or they think it's modernized in directions that they don't like, in one way or another. But everyone has their own tastes. But I'm definitely trying to do with Decker what HyperCard tried to do in the sense of making something that was beginner-friendly and accessible, a tool that was easy to get into, but that had a lot of headroom in terms of what it could creatively enable. And I also try to embody some of the things that I thought were really good about Flash. So HyperCard was always trapped on a local computer. And specifically, it was always trapped on a Macintosh computer, which often was a pretty expensive option in its day, even though they were really nice. With Decker, decks will run on a huge range of devices. They can be shared as easily as a hyperlink. And I've been making a lot of effort to try to make the Decker platform grow both forwards and backwards in time, in a sense. I'm continuously trying to get it to be usable on older devices that might be considered e-waste, as well as newer devices. So that no matter what you have gathering dust in your closet or whatever you fished out of a trash can, ideally, you should be able to run Decker on that and try other people's decks on that.
00:57:30 [AB]
That should make it even more attractive for educational uses. Sure, in some countries, they might have the resources for providing the very best hardware for every child. But lots of places in the world, they can't necessarily afford that, being able to run on old things.
00:57:46 [JE]
Right. And so, for example, Decker takes advantage of a mouse with a scroll wheel and everything if you have one. But the entire application is designed so that it can be fully used on tablet devices. It has a custom soft keyboard. Everything that you can do with a mouse, you can also do with gestures. There are certain minor things that I've intentionally left out of the system because they would, in my opinion, lead to making decks that would be less accessible on touch devices. For example, I have so far intentionally included hover-based functionality. Because if you're using a touch screen, there's not really such a thing as a hover event. There's long clicks or pressure clicks or whatever. But by targeting a common denominator of touch devices and desktop computers, by being accessible to machines that don't have keyboards, this means that if somebody buys the cheapest Android tablet they can get on AliExpress, there's a pretty good chance that you can at least get WebDecker working on it. And in the future, I want to have a native Android version that will mean that even on very, very humble hardware, you'll get a good editing experience. As good as I can do.
00:59:09 [BT]
So does that mean you don't have hover functionality in Decker?
00:59:13 [JE]
Not currently. But I should point out that if you really want to do something like that, there are ways to get around it. So I touched earlier on the danger zone. Basically, this is a place that I put features that cannot be used portably or necessarily safely. When you're using -- so this is an opt-in feature when you build native Decker. By default, decks are sandboxed. And if you want to do things like interact with the local file system, the user has to give affirmative consent and be aware that the program is trying to do these things. But sometimes that's not very practical for writing a utility program for yourself. So you can build it with the danger zone enabled, and then you have raw file system access. You can invoke utilities, shell programs, and collect their output. So if you want to curl something and hit a web API, you can do those things. And in WebDecker, there's a different danger zone that likewise is opt-in. And it lets you inject JavaScript into the browser. And then you can access and wrap whatever web APIs you want to access. So if you wanted to grab additional events and route them into Decker, there's a relatively straightforward module or way you can do that. But the cost, of course, is that if you take advantage of low-level JavaScript features, then you're welding yourself to a web browser. And those same experiences will not work in native Decker. So I provide a platform that has a uniform, portable substrate that, to the best of my efforts, works consistently on all of these platforms. And then on a specific platform, if you want to opt into more, there are mechanisms that you can do that.
01:01:20 [BT]
So, John, why do you do all of this? Like, is it exploration? Is it invention? Is it just creativity? Is that what your motivation is?
01:01:29 [JE]
Well, it's because I want there to be an easier way to make interactive stuff and share it. Like, I was starting to allude to
01:01:38
What?
01:01:39 [JE]
Flash had different than HyperCard was that it was so much easier to share things made with Flash. But what Flash lacked was you needed these elaborate development tools in order to make a Flash experience. And then you ship it to users. And then the users, they can play it and enjoy it. But if they want to modify it, it's going to be extremely painful or maybe impossible. So, Decker is doing the shareability of Flash with the user plasticity of HyperCard within certain technology constraints that I can't personally change, like some of the things that browsers can and cannot do. But it's a plastic, accessible medium. I guess, like, in the late '90s and early 2000s, there was a lot of interest in multimedia, where we're combining text and video and interactivity. And even though web browsers clearly have all of the latent capabilities to build multimedia experiences, and some people have made some really fantastic educational websites that work that way, in most of the places that an end user can host this dreaded word "content" online, it has to be a picture or a video or an audio file or text. You know, plus or minus a few things. But none of those are interactive general formats. There aren't very many places online where you can make things that are interactive. And there aren't very many tools for making interactive things that are, like, really beginner accessible and usable on old machines and so on. It's not a completely barren environment. There are tools that I found as inspirations, like PuzzleScript, like Pico-8, like Bitsy, like Twine. [06] And I've been, over time, since in some cases Decker is kind of more general than Twine or Bitsy, I've been working on bridges to allow you to use those tools together. But there's a lot of room at the bottom and a lot of ways that we could empower computer users to be more creative and have a greater ability to just cook home meals and tailor their computing environments to their own needs and preferences.
01:04:12 [BT]
And you've called the bridge between Twine to Decker "twee," which I get to say, which I love that word, "twee."
01:04:18 [JE]
Yeah, just, I guess, as another piece of background, Twine is a very popular environment for making choice-based interactive fiction. It lets you sort of author your game in a nice graph editor. And there are a variety of different plugins you can use that sort of give you different languages and markups for describing games. And I made a plugin for Twine and an associated module for Decker that gives you a common story format that both of those environments can work in. So you can author a choice-based game in Twine and then bring it into Decker and mix it with Decker's multimedia capabilities. Or you could simply write a game in Twine but have access to Lil if that's something that you like.
01:05:06 [CH]
Adám, I think you had a question or a comment earlier. I'm not sure if you've...
01:05:10 [AB]
No, it was just a technicality. You mentioned the example of these eyes following the mouse.
01:05:17 [ML]
I was going to ask the same thing.
01:05:19 [AB]
I don't know what Marshall wanted to ask about.
01:05:21 [ML]
We want to know what happens on a touchscreen.
01:05:23 [AB]
Yeah.
01:05:26 [JE]
Well, I mean, that's an example of something that, like, I can't perfectly abstract all of the differences between these things. There is a interface that you have access to from Decker called Pointer, which gives you information about the last place that the cursor was seen. So on touchscreens, you don't necessarily get a continuous access to it. And so it'll just be pointing at the last place that you've tapped or swiped or something. And on a desktop machine, you always have a cursor somewhere. So the behavior is a little bit different. But I try to make it so that as much as possible, the building blocks that you have tend to work the same in different environments with certain escape hatches that are just necessary. Like an example of this would be Decker does not directly expose keyboard down events or keyboard up events. You don't have raw information about a keyboard because Decker is used on devices that don't necessarily have keyboards. But you can associate buttons with shortcuts. So you could have a physical button on screen that you could tap or you could hit some key on your keyboard that does the same thing as clicking it. And if you really want to, you could hide those buttons or tuck them away off the edges of the card and just pretend that you have a keyboard driven game. So that's an example of where the defaults are accessible. And if you really want, you can sort of contort it into a way that won't work the same on different devices.
01:07:08 [AB]
So in the same way, you could potentially make hover effects as well by tracking the location of the cursor and then painting on top something as if it was a hover effect. >
01:07:18 [JE]
Exactly. And a few people have made contraptions that encapsulate the idea of it's a button that has a hover label that shows up. It's just not baked into Decker because it's totally fine if that sort of thing is possible. But it shouldn't be directly on the happy path because it's something that won't work on different devices or won't work the same.
01:07:42 [BT]
How big is the community right now? Just roughly, are we talking about tens, hundreds, thousands of people doing it?
01:07:50 [JE]
There are dozens of us.
01:07:51 [BT]
Dozens. More than tens.
01:07:54 [JE]
Yeah. We have a handful of very active users in the community forum and people that are a little bit more in the periphery but consistently making stuff. And every time we host a jam, we get a lot of new first timers. So I would say it's slowly growing. Because I'm really targeting a lot of people that aren't necessarily programmers or in many cases aren't necessarily people who think of themselves as a person who can make games or a person who can make interactive media, there's a real big challenge in outreach to finding people who would be interested in this and nurturing them and allowing them to develop comfort with trying to do something that could be very, very new to them. And of course, we also get some people who are seasoned users of other sorts of tools, who have made interactive fiction before or are just code golf enthusiasts that just want to try a new programming language in this weird environment. There's room for all kinds. But right now, a lot of the focus is on people who are just interested in dipping their toes into programming for the first time.
01:09:19 [BT]
And generally people, from what I've seen in the decks that have been created in some of the contests, highly creative people. They're definitely "yes and" as opposed to "no" people. They look at things and they try and create things with them. It's quite an interesting environment.
01:09:40 [JE]
Yes. I'm very, very proud of the community that we've managed to build so far. And I have high hopes for what we're going to be able to do over time as the tool gets better, as the educational materials get better, as we successfully outreach into more pockets and communities. And one of the things that's really amazing about these thing jams is every time somebody tries something totally new that nobody has seen before, and there's a lot of discussion around like, "Wow, you could do that in Decker? I had no idea." And then that gets people's minds going. They start thinking about some new project that they hadn't previously considered doing. I love reading comments by users that say something like, "A year ago, I never thought that I would be making visual novels. But now I'm sitting here writing down ideas and sketching doodles for this project. And this is the thing that I can do now."
01:10:43 [BT]
Yeah. The comments I've seen echo that. There's a lot of exploration going on. There's a lot of empowerment going on, I guess, for lack of anything else. It's--
01:10:56 [JE]
User empowerment is extremely important, particularly in today's landscape, where there are so many things that are just not about being open, not about being hackable. This is as open as I can make it, as flexible as I can make it. And it's an ongoing project. It'll continue to evolve.
01:11:17 [BT]
And you've taken a strong position on LLMs and their interaction with Decker.[07]
01:11:22 [JE]
It's definitely-- there are a lot of politics around this, but I just see it as not fitting in with what I'm trying to do.
01:11:31 [AB]
Wait, does Bob know something about this that we haven't heard about? Did I miss something?
01:11:35 [JE]
Specifically, he's referring to the fact that I've excluded-- one of the few rules that I have for the Thing Jams is, please don't make use of generative models in creating this content. And there's a lot that could be said about that. But in general, a lot of the people in the Decker community are artists and creatives, or budding artists and creatives. And I think that it goes without saying that these are communities that have not been treated very well by the tech giants that are harvesting their work in order to build these models. Again, it's a very long discussion.
01:12:22 [AB]
You don't have to go into it. I was just-- I wasn't aware of that rule. I don't think we mentioned it before.
01:12:27 [JE]
Yeah, it's just one of the things to call out. And as they say, it's basically just about making a more welcome environment. And it doesn't hurt that it's an opinion that I agree with.
01:12:43 [CH]
Yeah, there's a checkbox now that is at the top of my YouTube creator thing or whatever. And it said, you can now choose if your videos are going to get trained or used for training. And I was like, I can now choose? There was not for a second that they weren't already using the corpus of whatever, the billions of hours of content. Anyways, it was just like this nice little checkbox. You can now choose. It's like, Ok , well, as if there was-- I had a choice before, right?
01:13:15 [JE]
Yeah, I mean, it's very nice that Microsoft and all their magnanimity decided to train a language model on all of the code that I have put on GitHub that has a license, that conveniently ignore that license, and then offer products derived from it. But what are you going to do? I'm an individual.
01:13:37 [BT]
Join the Decker community.
01:13:40 [CH]
Yeah. On that note. Well, I mean, technically when this comes out, I think the Deck Month that is taking place over the month of December will have finished. But there will be future Deck Months. So maybe the next time you're doing one of these, shoot us a reminder and we'll make sure to announce it. And hopefully we can get some new people involved. Although, like you said, I guess we have a good target audience. But you're probably trying to reach people that aren't listening to this podcast on top of the people that are listening to this podcast. But I'm sure that the creatives, there's a bunch of them somewhere else.
01:14:21 [JE]
I really want to stress that I don't believe that there's a difference between programmers and creative people. I don't think there's a difference between art and engineering.
01:14:29 [ML]
Some of our listeners aren't actually robots.
01:14:33 [JE]
And I think that more voices from more diverse areas of interest will always be enriching this community. So if you don't think of yourself as a visual artist, please don't use that as a reason to overlook Decker and not give it a try. There's room for everybody.
01:14:53 [BT]
And we have the cold open.
01:14:58 [CH]
I was going to say that's a perfect way to end this podcast. But I guess it's going to be a perfect way to start this podcast as well.
01:15:04 [BT]
Bookends.
01:15:05 [CH]
If you have questions, comments, thoughts, you can reach us at--
01:15:10 [BT]
Contact@arraycast.com. [08] We are happy. We are interactive. We are willing to take your suggestions.
01:15:16 [ML]
We're almost as interactive as these decks on John's website.
01:15:19 [BT]
Oh, yeah. Our interactivity loop is a little extended from that. It's not quite that immediate. But we are interactive. We do respond. We do read. And we thank people who send them in. And we thank our two transcribers, Igor and Sanjay, for the work that they do as well. As well as Adám, who does the initial pass and puts all the nice timestamps on everything. So thanks to everybody for that.
01:15:46 [CH]
Thank you for coming on, John. It's always a blast. And I think, too, now that you are, I think, four-time guest, one-time guest panelist, you're up there with, I think, Henry Rich with the most-- we're going to have to use that group function to get a key value pair count of guests and appearances to figure out who's sitting at the top. But always a blast. And we'll have to have you on again in the future, whether that's to talk about Lil Decker, the new implementation of Lil, and some other language you wouldn't expect, or whatever your next project is. Yeah, until next time, thank you so much. This has been a blast.
01:16:21 [JE]
Thanks for having me.
01:16:22 [CH]
And with that, we'll say, happy array programming.
01:16:25 [ALL]
Happy array programming.
01:16:27 [Music]