Interesting to see Google starting to solicit reviews for apps that came with the phone, such as the… Phone.
Igore the click-batey headline: this is quite a good post. Really enjoyed it. And, on the whole, I agree with the author. Via Jim Nielsen’s notes
Day 26: critter
Watch out for these ones. #mbapr
UCL: The Simplifications Paid Off
The UCL simplifications have been implemented, and they seem to be largely successful.
Ripped out all the streaming types, and changed pipes to simply pass the result of the left command as first argument of the right.
"Hello" | echo ", world"
--> "Hello, world"
This has dramatically improved the use of pipes. Previously, pipes could only be used to connect streams. But now, with pretty much anything flowing through a pipe, that list of commands has extended to pretty much every builtins and user-defined procs. Furthermore, a command no longer needs to know that it’s being used in a pipeline: whatever flows through the pipe is passed transparently via the first argument to the function call. This has made pipes more useful, and usable in more situations.
Macros can still know whether there exist a pipe argument, which can
make for some interesting constructs. Consider this variant of the
foreach
macro, which can “hang off” the end of a pipe:
["1" "2" "3"] | foreach { |x| echo $x }
--> 1
--> 2
--> 3
Not sure if this variant is useful, but I think it could be. It seems
like a natural way to iterate items passed through the pipe. I’m
wondering if this could extend to the if
macro as well, but that
variant might not be as natural to read.
Another simplification was changing the map
builtin to accept
anonymous blocks, as well as an “invokable” commands by name.
Naturally, this also works with pipes too:
[a b c] | map { |x| toUpper $x }
--> [A B C]
[a b c] | map toUpper
--> [A B C]
As for other language features, I finally got around to adding support for integer literals. They look pretty much how you expect:
set n 123
echo $n
--> 123
One side effect of this is that an identifier can no longer start with a dash followed by a digit, as that would be parsed as the start of a negative integer. This probably isn’t a huge deal, but it could affect command switches, which are essentially just identifiers that start with a dash.
Most of the other work done was behind the scenes trying to make UCL easier to embed. I added the notion of “listable” and “hashable” proxies objects, which allow the UCL user to treat a Go slice or a Go struct as a list or hash respectively, without the embedder doing anything other than return them from a function (I’ve yet to add this support to maps just yet).
A lot of the native API is still a huge mess, and I really need to tidy it up before I’d be comfortable opening the source. Given that the language is pretty featureful now to be useful, I’ll probably start working on this next. Plus adding builtins. Really need to start adding useful builtins.
Anyway, more to come on this topic I’m sure.
Oh, one last thing: I’ve put together an online playground where you can try the language out in the browser. It’s basically a WASM build of the language running in a JavaScript terminal emulator. It was a little bit of a rush job and there’s no reason for building this other than it being a fun little thing to do.
You can try it out here, if you’re curious.
Thou Doth Promote Too Much
Manual Moreale wrote an interesting post about self promotion, where he reflects on whether closing out all his People and Blogs post with a line pointing to his Ko-Fi page is too much:
And so I added that single line. But adding that single line was a struggle. Because in my head, it’s obvious that if you do enjoy something and are willing to support it, you’d probably go look for a way to do it. That’s how my brain works. But unfortunately, that’s not how the internet works. Apparently, the correct approach seems to be the opposite one. You have to constantly remind people to like and subscribe, to support, to contribute, and to share.
I completely understand his feelings about this. I’m pretty sure I’d have just as much trouble adding such a promotion at the bottom of my post. Heck, it’s hard enough to write about what I’m working on here without any expectation from the reader other than to maybe, possibly, read it. They’ve been relegated to a separate blog, so as to not bother anyone.
But as a reader of P&B, I think the line he added is perfectly fine. I think it’s only fair to ask people to consider supporting something where it’s obvious someone put a lot of effort into it, as he obviously has been doing with P&B.
As for where to draw the line, I think I agree with Moreale:
How much self-promotion is too much? Substack interrupting your reading experience to remind you to subscribe feels too much to me. An overlay interrupting your browsing to ask you to subscribe to a newsletter is also too much. Am I wrong? Am I crazy in thinking it’s too much?
I get the need to “convert readers” but interrupting me to sign up to a newsletter is just annoying. And I’m not sure “annoying” is the feeling you want to imbue in your readers if you want them to do something.
But a single line at the end of a quality blog post? Absolutely, go for it!
Some emus have moved into a nearby sanctuary a few weeks ago. I managed to catch a glimpse of one during my walk today. A rare treat indeed.
Day 25: spine #mbapr
Day 24: light #mbapr
I was snakily going to suggest a “HTML naked day” to complement both CSS and JS naked day, but then I realise that that’s the default for all modern web frontend development. 😏
👨💻 New post on Databases over at the Coding Bits blog: PostgreSQL LATERIAL Joins
Day 23: dreamy #mbapr
Simplifying UCL
I’ve been using UCL for several days now in that work tool I mentioned, and I’m wondering if the technical challenge that comes of making a featureful language is crowding out what I set out to do: making a useful command language that is easy to embed.
So I’m thinking of making some simplifications.
The first is to expand the possible use of pipes. To date, the only thing that can travel through pipes are streams. But many of the commands I’ve been adding simply return slices. This is probably because there’s currently no “stream” type available to the embedder, but even if there was, I’m wondering if it make sense to allow the embedder to pass slices, and other types, through pipes as well.
So, I think I’m going to take a page out of Go’s template book and
simply have pipes act as syntactic sugar over sequential calls. The goal
is to make the construct a | b
essentially be the same as b (a)
,
where the first argument of b
will be the result of a
.
As for streams, I’m thinking of removing them as a dedicated object type. Embedders could certainly make analogous types if they need to, and the language should support that, but the language will no longer offer first class support for them out of the box.
The second is to remove any sense of “purity” of the builtins. You may
recall the indecision I had regarding using anonymous procs with the
map
command:
I’m not sure how I can improve this. I don’t really want to add automatic dereferencing of identities: they’re very useful as unquoted string arguments. I suppose I could add another construct that would support dereferencing, maybe by enclosing the identifier in parenthesis.
I think this is the wrong way to think of this. Again, I’m not here to
design a pure implementation of the language. The language is meant to
be easy to use, first and foremost, in an interactive shell, and if that
means sacrificing purity for a map
command that supports blocks,
anonymous procs, and automatic dereferencing of commands just to make it
easier for the user, then I think that’s a trade work taking.
Anyway, that’s the current thinking as of now.
My spilling has bin partickualy bad todai!
If Alan has a problem, and Brett has a solution, but Brett’s solution is qualified with conditions that can’t be met by Alan, then Alan doesn’t have a solution.
Brett should probably just let go of this fact, rather than criticise Alan for not using his solution because of “conditions”.
Day 22: blue #mbapr
Day 21: mountain
Warburton, in the Yarra Ranges. #mbapr
🔗 Hiss!
Seeing @Miraz’s post about the Morepork reminded me of this poem by C. J. Dennis that was read to us as a kid. It was in this beautifully illustrated picture book, with thick borders full of, I guess, the illustrations of the subject’s imagination.
Imports And The New Model
Well, I dragged Photo Bucket out today to work on it a bit.
It’s fallen by the wayside a little, and I’ve been wondering if it’s worth continuing work on it. So many things about it that need to be looked at: the public site looks ugly, as does the admin section; working with more than a single image is a pain; backup and restore needs to be added; etc.
I guess every project goes through this “trough of discontent” where the initial excitement has warn off and all you see is a huge laundry list of things to do. Not to mention the wandering eye looking at the alternatives.
But I do have to stop myself from completely junking it, since it’s actually being used to host the Folio Red Gallery. I guess my push to deploy it has entrapped me (well, that was the idea of pushing it out there in the first place).
Anyway, it’s been a while (last update is here) and the move to the new model is progressing. And it’s occurred to me that I haven’t actually talked about the new model (well, maybe I have but I forgot about it).
Previously, the root model of this data structure is the Store
. All
images belong to a Store
, which is responsible for managing the
physical storage and retrieval of them. These stores can have
sub-stores, which are usually used to hold the images optimised for a
specific use (serving on the web, showing as a thumbnails, etc).
Separate to this was the public site Design
which handed properties of
the public site: how it should look, what the title, and description is,
etc.
There were some serious issues with this approach: images were owned by stores, and two images can belong to two different stores, but they all belonged to the same site. This made uploading confusing: which store should the image live on? I worked around this by adding the notion of a “primary store” but this was just ignoring the problem and defeated the whole multiple-store approach.
This is made even worse when one considers which store to use for
serving the images. Down the line I was hoping to support virtual domain
hosting, where one could setup different image sites on different
domains that all pointed to the same instance. So imagine how that would
work: one wanted to view images from alpha.example.com
and another
wanted to view images from beta.example.com
. Should the domains live
on the store? What about the site designs? Where should they live?
The result was that this model could only really ever support one site per Photo Bucket instance, requiring multiple deployments for different sites if one wanted to use a single host for separate photo sites.
So I re-engineered the model to simplify this dramatically. Now, the
route object is the Site
:
Here, the Site owns everything. The images are associated with sites, not stores. Stores still exist, but their role is now more in-line with what the sub-stores did. When an image is uploaded, it is stored in every Store of the site, and each Store will be responsible for optimising it for a specific use-case. The logic used to determine which Store to use to fetch the image is still in place but now it can be assumed that any Store associated with a site will have the image.
Now the question of which Store an image should be added to is easy: all the them.
Non-image data, such as Galleries and Designs now live off the Site as well, and if virtual hosting is added, so would the domain that serves that Site.
At least one site needs to be present at all time, and it’s likely most instances will simply have a single Site for now. But this assumption solves the upload and hosting resolution issues listed above. And if multiple site support is needed, a simple site picker can be added to the admin page (the public pages can will rely on the request hostname).
This has been added a while ago, and as of today, has been merged to
main
. But I didn’t want to deal with writing the data migration logic
for this, so my plan is to simply junk the existing instance and replace
it with the brand new one. But in order to do so, I needed to export the
photos from the old instance, and import them into the new one.
The export logic has been deployed and I’ve made an export it this
morning. Today, the import logic was finished and merged. Nothing
fancy: like the export
it’s only invokable from the command line. But
it’ll do the job for now.
Next steps is to actually deploy this, which I guess will be the ultimate test. Then, I’m hoping to add support for galleries in the public page so I can separate images on the Folio Red Gallery into projects. There’s still no way to add images in bulk to a gallery. Maybe this will give me an incentive to do that next.
Day 20: ice #mbapr
A small visitor is back, enjoying the sun on my kitchen tiles. 🦎