Building with Parenscript and Preact: Difference between revisions

Jump to navigation Jump to search
no edit summary
No edit summary
No edit summary
Line 52: Line 52:
= Implementation =
= Implementation =


I implemented draggable and droppable cards using GSAP (since that's what Holger uses), wrapped in <code>use-effect</code> It's a pretty lightweight way to animate and tween everything which is really cool. Since the cards are all positioned by this system, I can tweak values in the editor and they all animate into their new places, which is fun and just feels powerful for some reason.
I implemented draggable and droppable cards using GSAP (since that's what Holger uses), wrapped in <code>use-effect</code>. It's a pretty lightweight way to animate and tween everything which is really cool. Since the cards are all positioned by this system, I can tweak values in the editor and they all animate into their new places, which is fun and just feels powerful for some reason.


<gif>
<gif>
Line 72: Line 72:
= The Good =
= The Good =


I loved the flexibility of being able to include new syntax when it was appropriate. The game state is represented using an object then when I need to update, I perform a <code>structured-clone</code> on and then pipe through various modification functions, and then into <code>set-board-state</code>
I loved the flexibility of being able to include new syntax when it was appropriate. The game state is represented using an object then when I need to update, I perform a <code>structured-clone</code> on and then pipe through various modification functions, and then into <code>set-board-state</code>:


<syntaxhighlight lang="lisp">
<syntaxhighlight lang="lisp">
Line 82: Line 82:
</syntaxhighlight>
</syntaxhighlight>


Another thing that came in pretty handy (with caveats I'll mention later) is Parenscript's implementation of <code>loop</code> I always find myself in other languages wishing I had CL's <code>loop</code> it just blows everything else out of the water, it is so supremely useful. If I ever make my own dream language that's a mashup of everything I like from other languages, that's definitely going in there. DCGs from Prolog as well; every time I have to write some code that vaguely resembles parsing or decoding, I wish I was in Prolog... but I digress.
Another thing that came in pretty handy (with caveats I'll mention later) is Parenscript's implementation of <code>loop</code>. I always find myself in other languages wishing I had CL's <code>loop</code>; It just blows everything else out of the water, it is so supremely useful. If I ever make my own dream language that's a mashup of everything I like from other languages, that's definitely going in there. DCGs from Prolog as well, every time I have to write some code that vaguely resembles parsing or decoding, I wish I was in Prolog... but I digress.


Lyn mentions it too in his article but Paredit makes things massively easier to work with. I always thought JS gets pretty ugly real quick with all the braces and ellipsis and arrows piling up.
Lyn mentions it too in his article but Paredit makes things massively easier to work with. I always thought JS gets pretty ugly real quick with all the braces and ellipsis and arrows piling up.
Line 92: Line 92:
For one, a component will always remount if it changes position in the DOM. If your component is storing state inside itself, this means that if for whatever reason it changes location in the DOM, that state is just thrown away. And that really sucks, because I want my deck of 52 cards to be draggable, droppable with animation, and some other things that they need to store state for, so my "solution" was to simply position each card absolutely, and deal with the layout myself. It's actually not too big of a deal since card cascades are pretty simple, but still.
For one, a component will always remount if it changes position in the DOM. If your component is storing state inside itself, this means that if for whatever reason it changes location in the DOM, that state is just thrown away. And that really sucks, because I want my deck of 52 cards to be draggable, droppable with animation, and some other things that they need to store state for, so my "solution" was to simply position each card absolutely, and deal with the layout myself. It's actually not too big of a deal since card cascades are pretty simple, but still.


React (and Preact) compare arrays shallowly when in the dependencies array of <code>use-effect</code> This means that if you pass an array as a prop and then give it to <code>use-effect</code> it will simply re-run the effect every single time... apparently the go-to workaround is to pass <code>JSON.stringify(the_array)</code> to the list instead. That's the kind of bizarre JS stuff I wish I could escape from, which leads me to my next section:
React (and Preact) compare arrays shallowly when in the dependencies array of <code>use-effect</code>. This means that if you pass an array as a prop and then give it to <code>use-effect</code> it will simply re-run the effect every single time... apparently the go-to workaround is to pass <code>JSON.stringify(the_array)</code> to the list instead. That's the kind of bizarre JS stuff I wish I could escape from, which leads me to my next section:


= The Ugly =
= The Ugly =
Line 103: Line 103:
}}
}}


Parenscript is fundamentally flawed. It's a super-lightweight papering-over of JavaScript, and you become aware of that harsh reality immediately. It makes an attempt to look like the surface syntax of Common Lisp while maintaining none of its semantics, so you kind of have to juggle in your mind the JavaScript you want to get, the Parenscript you have to write, and the Common Lisp that would do something else if executed as CL. It's especially odd since JS has no cons cells, and Parenscript doesn't try to provide them-- <code>(cons 1 nil)</code> just becomes <code>cons(1, null);</code> So it looks superficially a lot like CL, but isn't like it semantically at all. On top of that, Parenscript has a few bugs: it will just miscompile things sometimes, specifically its <code>loop</code> construct, and it has a bad habit of not declaring variables when you use <code>let</code> which doesn't work in <code>use strict"</code> mode.
Parenscript is fundamentally flawed. It's a super-lightweight papering-over of JavaScript, and you become aware of that harsh reality immediately. It makes an attempt to look like the surface syntax of Common Lisp while maintaining none of its semantics, so you kind of have to juggle in your mind the JavaScript you want to get, the Parenscript you have to write, and the Common Lisp that would do something else if executed as CL. It's especially odd since JS has no cons cells, and Parenscript doesn't try to provide them-- <code>(cons 1 nil)</code> just becomes <code>cons(1, null);</code>. So it looks superficially a lot like CL, but isn't like it semantically at all. On top of that, Parenscript has a few bugs: it will just miscompile things sometimes, specifically its <code>loop</code> construct, and it has a bad habit of not declaring variables when you use <code>let</code>, which doesn't work in <code>use strict"</code> mode.


= Conclusion =
= Conclusion =


One thing I've always thought about macros in Common Lisp is that you often don't need them because the language is already so rich on its own. A lot of the times I find myself wanting to use a macro is when I'm using other languages that don't have them. In this case, worlds collide since the actual implementation language is pretty spartan, but it can be extended with the full power of Lisp. Which means that usually when I'd wish for macros I'd sigh wistfully and start copy-pasting, but now I can actually have them. It's pretty cool, and combined with JavaScript's dynamic nature, and my home-grown interactive development environment, it does feel kinda like you're writing Lisp... until the illusion is inevitably broken by semantic differences. But I actually do like it a lot anyway, it's a lot more fun than writing straight JS, that's for sure.
One thing I've always thought about macros in Common Lisp is that you often don't need them because the language is already so rich on its own. A lot of the times I find myself wanting to use a macro is when I'm using other
 
The site is up at https://online-freecell.com, check it out.

Navigation menu