inessential.com

Brent Simmons’s weblog.

Evergreen Status 22 Aug 2017, 1:22 pm

The current goal is a Spring 2018 release of Evergreen 1.0. Which is rather ambitious, I know, and I wouldn’t be shocked if it was Spring 2019. But that’s the goal.

The build is currently broken, has been broken for months, and will continue as broken for at least another few weeks.

Here’s the scoop: I decided to do syncing in 1.0. It will probably be just one system at first (most likely FeedBin, since that’s what I use) — but this meant looking at the data and database level and figuring out what’s needed to make it usable when syncing. I’m in the middle of making the needed changes.

(Originally each syncing system was going to have its own database code, but I realized that that would be foolish.)

And, because I’m such a weird database-code-loving freak, I’m not using Core Data. (Total dummy, me. Don’t tell me.) An example is DatabaseLookupTable.swift, which manages relationships.

* * *

Progress is slow, since I don’t get to work on it every day, and even when I do it’s often just for half an hour. There are occasional days where I get a few hours. But, except when I’m on vacation, progress is steady — and that’s how you get things done. (It helps to be obsessed.)

(Frontier, meanwhile, is on the back burner — I picked Evergreen to ship first just because it was further along. I’ll get back to it.)

Republicans Have Been Playing with Racist Fire For All of my 49 Years 18 Aug 2017, 1:28 pm

From Nixon’s law-and-order and “silent majority” and southern strategy; to Reagan’s campaign kickoff in Philadelphia, Missouri, his “welfare queens,” his war on drugs; to the Willie Horton ad, the culture war, Rush Limbaugh, gerrymandering, voter suppression, birtherism, and “calves the size of cantaloupes” — Republicans have, for my whole life, very deliberately and consciously cultivated white grievance and racism.

I was born in 1968. This has been going on the entire time.

I always figured Republicans were playing with these ugly matches because it was a means to an end: it was how they could gain enough power to do what their donors actually want — which is to sell off America piece-by-piece for their private, short-term gain.

But then comes Trump, and then the racism is the point.

Well, he’s just about the same economically. Sure. But his economic policies, such as they are, are a mixture of greed and pandering to the people who got him where he is.

It’s the racism, stupid.

* * *

So I don’t feel particularly moved when Republicans decry the Nazis and nationalists at the rally last weekend. They should do that — it’s the least they could do.

But it seems like only when actual swastikas show up do they say anything. Otherwise it’s not racism, they say — it’s combatting voter fraud. It’s about state’s rights, or fiscal conservatism, or religious freedom. It’s always the dog whistle.

But then the wolves appear — on cue! summoned! — and then they furrow their brows.

They need to do better. Much, much better. Anyone who cares about their country would do better.

Square World 4 Jul 2017, 12:02 pm

I keep thinking that the election of Trump has turned us all into conservatives.

I mean “conservative” in a more old-fashioned (and I think truer) sense than what is generally thought. I don’t mean Republican — the Republican party is a radical reactionary party, not at all conservative.

I mean that we liberals and progressives have learned that national respect for truth, expertise, and empiricism is something we’re in danger of losing. It’s not a given. We can’t take rule of law for granted; we can’t assume our institutions won’t fly apart.

Everything good we’ve built is also the foundation on which further progress is made.

The fight right now is to preserve those good things.

* * *

When I was 16 years old I wanted to épater la bourgeoisie and grow up to be a writer (I kind of did) and wear all black (I often do) and smoke Galouises (I never do).

I was in favor of burning down everything and rebuilding a just civilization from scratch. Barring that, I just wanted to be seen as a guy in favor of that kind of thing. :)

But now, at age 49, it seems like I just want people to accept facts and science, and to stop lying.

* * *

At 16 years old I had contempt for the people who were slow and careful, who dotted i’s and crossed t’s, whose watchword was diligence, who displayed patience, who played the long game.

After all, every second of delay was another broken heart. Every minute was unjust.

But I was a bullshit artist at that age, and I didn’t know or care that it took work — slow, steady, and unglamorous — to build good things that are hard to break.

And while I worry like crazy about our nation, I have some faith — because I choose to, because it’s the moral choice — that the square world that I used to hate, that I now love, will get the job done.

I don’t mean just Robert Mueller and his investigation, though I do include him. I mean all the people working — most of them quietly, some flashily, but all with care and good faith — toward preserving what we have, so that we can resume our long journey toward living up to our founding ideals.

* * *

What we have of national goodness, so incompletely realized, is fragile.

This Fourth of July I thank Square World for their work, and hope to be able to say of myself that I am part of that world.

James Dempsey and the Breakpoints Benefit App Camp for Girls 2 Jun 2017, 10:05 pm

On Wednesday night I know where I’ll be — playing keyboard for a few songs at the James Dempsey and the Breakpoints concert benefitting App Camp for Girls.

You should get tickets. It’s a fun time for a great cause.

Bonus: James writes about how this concert is full circle for him. It’s a special night.

Evergreen Diary #1: Open Source 1 Jun 2017, 5:27 pm

Evergreen is a new feed reader for Macs. It’s not actually done yet — in fact, it’s not even alpha yet, much less beta. It’s still in the painful-to-use stage, for sure.

I’ve been working on it (among other things) on nights and weekends for a couple years. For much of the time I planned to make it a for-pay app — the plan was a free Lite version and a for-pay version.

But as time went on I was less and less motivated to make a for-pay app. Doing all that stuff — dealing with licenses, money, a store, support, and everything else that goes along with a commercial app — just didn’t sound like any fun, and it would have taken time away from actually working on the app, which is all I really want to do. I just don’t have time to spare.

So I decided to make it free and open source. (The code is up on GitHub.) This fits with my goals:

  • Promoting feed-reading as part of promoting the open web.
  • Publishing a bunch of feed-reading code and an example Mac app that other developers can use.
  • Giving me something to write about on this blog.

I like developing in public. Publishing the code makes it feel like a performance, a kind of tightwire act. Which suits me.

* * *

The one thing that almost held me back from making it open source was the effect on other developers. There are for-pay Mac feed readers, after all, and I don’t want to take anything away from them.

And I don’t want to send the message that software ought to cost nothing.

I think that making it open source makes it an obvious special case. There is at least one other open source Mac feed reader, and there are other open source Mac apps, and I don’t think that these projects are fueling the race to the bottom with app pricing.

I went over and over this decision for months. It wasn’t easy! But in the end I decided it’s a good thing, and there are always good reasons not to do a good thing.

* * *

The app doesn’t have any icons yet. Brad Ellis, who I’ve worked with before on some versions of my previous feed reader, and who is my favorite designer, is working on icons.

Brad is not only my favorite designer, he’s the favorite designer of people who thought they might be my favorite designer. :)

* * *

At some point it will sync with some existing systems (such as Feedly, FeedBin, and similar) — but probably not till after 1.0, though as top priority.

I have no plans to make an iOS version (though anything could happen). The plan is to make it a great Mac app. Period. But if it syncs with Feedly and so on, then you could use some other reader on iOS and it would sync with Evergreen.

* * *

There is a road not taken here that’s worth exploring, though probably not by me (for reasons of time).

I would love to see a casual feed reader (as opposed to productivity-style) that just provides a timeline, with new stuff at the top. The idea is to make something like a Twitter client but for feeds. You’d get a list of articles, and when you want to read something you’d click (or whatever) to open the article in your browser.

Such an app wouldn’t have per-article read/unread status — instead it would maintain a high-water mark, the date of the newest item you’ve seen in the timeline.

For a little while I was planning to do both styles of reader, since so much of the code would be shared. But that was overly ambitious, so I dropped the idea.

But you could do it.

* * *

I made a Twitter account: evergreen_mac. Though I have no fondness for Twitter, it seems like app makers need to be accessible that way. Most Evergreen users will probably be on Twitter.

But you don’t have to use it: you can report bugs and make feature requests via GitHub. And that way they’re in the system, which is good.

You can also email me: I’m brent at the domain name that appears in the link that starts the first sentence of this post.

“App: The Human Story” Screening in San Jose 26 May 2017, 12:57 pm

Here’s the scoop. It’s Sunday, June 4 at 5 pm. There’s a panel afterward with a bunch of people from the movie (including me).

You can get tickets. You should get tickets — the event benefits App Camp for Girls.

Plus I think you’ll enjoy it. :)

JSON Feed 17 May 2017, 1:22 pm

I was hesitant, even up to this morning, to publish the JSON Feed spec.

If you read Dave Winer’s Rules for standards-makers, you’ll see that we did a decent job with some of the rules — the spec is written in plain English, for example — but a strict application of the rules would have meant not publishing at all, since “Fewer formats is better.”

I agree completely — but I also believe that developers (particularly Mac and iOS developers, the group I know best) are so loath to work with XML that they won’t even consider building software that needs an XML parser. Which says to me that JSON Feed is needed for the survival of syndication.

I could be wrong, of course. I admit.

Feed Reader Starter Kit

See my RSXML repository for Objective-C code that reads RSS, Atom, and OPML. I’ve done the work for you of supporting those formats. Go write a feed reader! Seriously. Do it.

I planned to have a JSON Feed parser for Swift done for today, but other things got in the way. It’s coming soon. But you probably don’t actually need any sample code, since JSON is so easy to handle.

Feedback so far

Feedback has been interesting so far. Some questions on the GitHub repo need answering.

Some people have said this should have happened ten years ago, and other people have said that they hate how developers jump on the latest fad (JSON).

And some people really like the icon:

Microformats

One of the more serious criticisms was this: why not just support the hAtom microformat instead? Why do another side-file?

My thinking:

My experience as a feed reader author tells me that people screw up XML, badly, all the time — and they do even less well with HTML. So embedding info in HTML is just plain too difficult. In practice it would be even buggier than XML-based feeds.

And there are other advantages to decoupling: a side-file can have 100 entries where there are only 10 on an HTML page, for instance. A side-file can have extra information that you wouldn’t put on an HTML page. And yet, despite the extra information, a side-file can be much smaller than an HTML page, and it can often be easier to cache (since it’s not different based on a logged-in user, for instance).

Microformats sounds elegant, but I don’t prize elegance as much as I value things that work well.

Frontier Diary #8: When Worlds Collide 1 May 2017, 1:34 pm

I spent the weekend making a bunch of progress on the compiler. It has two pieces: a tokenizer, which I created by rewriting the original C code (langscan.c) in Swift, and a parser.

The parser in OrigFrontier was generated by MacYacc, which is similar to Yacc, which is similar to Bison, which is on my Mac. The thing about the parser is that it’s C code, and the rest of the app is Swift.

How do you bridge the two worlds? Easy answer: with Objective-C, which is a superset of C and which plays nicely (enough) with Swift.

So I renamed langparser.y — the rules file that the parser generator uses — to langparser.ym so that Xcode would know to treat the generated parser source as Objective-C. I edited it slightly, not to change the grammar rules but to change how nodes are created (as return values rather than via inout).

I also made my CodeTreeNode class, written in Swift, an Objective-C class so that it would be visible to my Objective-C code.

And then, finally, I started a build…

…and then it stopped with an error because the parser places my CodeTreeNode in a C union, which isn’t allowed in ARC.

Crushed.

* * *

I think I have three options:

  1. Go down the rabbit hole of figuring out how to get the parser to work with ARC.
  2. Go with the flow: have the parser generate nodes that are, as in OrigFrontier, C structs. The last compilation step would be Objective-C code that translates that tree of C structs into a tree of CodeTreeNode objects, and then disposes the C-struct-node-tree.
  3. Write the parser by hand, in Swift.

My thinking:

I could waste a ton of time on #1, and bending tools in that way can be pretty frustrating work when they refuse to bend.

With #2 I’d feel a bit weird about the redundancy: building a tree and then building a copy of that tree with a different type of object.

My heart tells me #3 is the answer. After all, I’ve already done the tokenizer. How hard would it be to parse those tokens into a code tree? I could skip C and Objective-C altogether and stay in Swift. And it would be so fun. (Because that’s precisely the style of weirdo I am.)

* * *

But the real answer is #2. Writing a parser by hand would take way longer than I think. Given enough tests, it shouldn’t be a huge source of bugs, but still.

The thing about #2 is that yes, it’s redundant, it’s doing more work than it needs to, ideally — but my bet is that it would still be so fast that you wouldn’t be able to tell the difference. Computers are so good at this kind of thing. It’s not like reading files or networking; it’s just in-memory traversal and creating/releasing things.

You remember in Indiana Jones that guy with the twirling swords, and Indy gives that look and then just shoots him? The second option is the Indiana Jones solution.

Update 2:05 pm: Two people have already written me to recommend ANTLR. So I will definitely give that a look. It might be exactly what I need.

Frontier Diary #7: Pretty Much Everything Throws 27 Apr 2017, 1:30 pm

A script can throw an error, either intentionally (via the scriptError verb) or by doing something, such as referencing an undefined object, that generates an error.

OrigFrontier was written in C, which has no error-throwing mechanism, and so it worked like this: most runtime functions returned a boolean (for success or failure), and the return value was passed in by reference. If there was an error, the function would set a global error variable and return false. The caller would then have to check that global to see if there was an error, and then do the right thing.

This was not unreasonable, given the language and the times (early ’90s) and also given the need to be very careful about unwinding memory allocations.

But, these days, it seems to me that Swift’s error system is the way to go. There’s just one downside to that, and it’s that I have to do that do/try/catch dance all over the place, since pretty much any runtime function can throw an error.

Even the coercions can throw, so last night I changed the Value protocol so that asInt and so on are now functions, since properties can’t throw (at least not yet).

The extra housekeeping — the do/try/catch stuff — kind of bugs me, but it’s honest. I considered making script errors just another type of Value — but that meant that all those callers have to check the returned Value to see if it’s an error, and then do the right thing. Better to just use Swift’s error system, because it makes for more consistent code, and it makes sure I’m catching errors in every case.

It also means I’m not multiplying entities. A Swift error is a script error, and vice versa.

* * *

Working on this code is like applying the last 25 years of programming history all at once.

A completely different type of error is a bug, and I’m certain to write a bunch of them, because that’s how programming goes.

That’s where unit tests come in. Frontier has long had a stress-test suite of scripts — you’d launch the app, run that suite, wait a while, and see if there are any errors. This was critically helpful.

But OrigFontier didn’t have unit tests at the C code level. The new version does. (Well, I’ve started them anyway.) This means I can more easily follow Rule 1 — the no-breakage rule — and can also more easily follow Rule 1b — the don’t-break-Dave rule.

PS I’ve added a collection page for the Frontier Diary, as I did with earlier diaries. There’s a link to it in the footer of every page on the blog.

Frontier Diary #6: Ballard, from the Parallel Universe 26 Apr 2017, 1:04 pm

In another universe I didn’t decide to port Frontier — instead, I started over from scratch on an app inspired by Frontier.

In that universe, the new scripting language, descended from UserTalk, is called Ballard. And it’s documented.

My Microblog 25 Apr 2017, 2:27 pm

I’m on Manton‘s cool new microblogs system. Here’s where you can follow me, once you’re on the system: http://micro.blog/brentsimmons.

And here’s my microblog: http://brent.micro.blog/. (Which you can read using RSS, whether you’re on the system or not.)

I wrote about three-quarters of my own single-user microblog system — and then stopped because I didn’t feel like running a server and because Manton’s service is so good.

Frontier Diary #5: Values and Progress on the Language 25 Apr 2017, 1:26 pm

I put the Frontier repository up on GitHub.

(The build is currently broken. This is bad discipline, but since it’s still just me, I forgive myself. Sometimes I run out of time and I just commit what I have.)

The repo has my new code and it also contains FrontierOrigFork, which is the original Frontier source with a bunch of deletions and some changes. The point is to give me 1) code to read and 2) a project that builds and runs on my 10.6.8 virtual machine.

The original code is in C, and the port is, at least so far, all in Swift. In the end it should be almost all in Swift, but I anticipate a couple places where I may need to use Objective-C.

Here’s one of the Swift wins:

Values

Since Frontier contains a database and scripting language, there’s a need for some kind of value object that could be a boolean, integer, string, date, and so on.

Original Frontier used a tyvaluedata union, with fields for the various types of values.

This is a perfectly reasonably approach in C. It’s great because you can pass the same type of value object everywhere.

Were I writing this in Objective-C, however, I’d create a Value protocol, and then create new value objects for some types and also extend existing objects (NSNumber, NSString, etc.) to conform to the Value protocol. This would still give me the upside — passing a Value type everywhere — while reducing the amount of boxing.

But: this still means I have an NSNumber when I really want a BOOL. Luckily, in Swift I can go one better: I can extend types such as Bool and Int to conform to a Value protocol.

This means passing around an actual Bool rather than a boxed boolean. I like this a ton. It feels totally right.

Other topic:

Language Progress

I’m still in architectural mode, where I’m writing just enough code to validate and refine my decisions. A couple days ago I started on the language evaluator — the thing that actually runs scripts.

It works as you expect: it takes a compiled code tree and recursively evaluates it. It’s not difficult — it’s just that it’s going to end up being a fair amount of code.

I’ve done just enough to know that I’m on the right path. (The Swift code looks a lot like the C code in OrigFrontier’s langevaluate.c. See evaluateList, for instance.)

The next step is for me to build the parser. I thought about writing a parser by hand, because it sounds like fun, and it would give me some extra control — but, really, it would slow me way down, so forget it.

OrigFrontier generated its parser by passing a grammar file — langparser.y — to MacYacc (there was such a thing!), which generated langparser.c.

I’ll do a similar thing, except using Bison (which is compatible with Yacc). Or, possibly, using the Lemon parser generator instead. Either way, I’ll want the generated code to be Objective-C. (Well, mostly C, but with Objective-C objects instead of structs.) (I don’t know of a generator that would create Swift code.)

This is completely new territory for me, and is exciting.

(Almost forgot to mention: I’ll need to write a tokenizer. This means porting langscan.c. I’ll need to do this first, since the parser generator needs it. So this is the real next step.)

Save $300 on CocoaConf Next Door 14 Apr 2017, 1:53 pm

My pals at CocoaConf asked me to remind you that the Early Bird sale ends in two weeks for CocoaConf Next Door — the one taking place in San Jose during WWDC.

I’ll be there. At least in the afternoons.

Check out the speakers list. Yummy, chewy, nutty speakers list.

Frontier Diary #4: The QuickDraw Problem and Where It Led Me 14 Apr 2017, 1:14 pm

In my fork of Frontier there are still over 600 deprecation warnings. A whole bunch of these are due to QuickDraw calls.

For those who don’t know: QuickDraw was how, in the old days, you drew things to the Mac’s screen. It was amazing for its time and pretty easy to work with. Functions included things like MoveTo, LineTo, DrawLine, FrameOval, and so on. All pretty straightforward.

These days we have Core Graphics instead, and we have higher-level things like NSBezierPath. QuickDraw was simpler — though yes, sure, that was partly because it did less.

* * *

I was looking at all these deprecation warnings for QuickDraw functions and wondering how I’m ever going to get through them.

I could, after all, convert all or most of them to the equivalent Core Graphics thing. But sheesh, what a bunch of work.

And, in the end, it would still be a Carbon app, but with modern drawing.

* * *

So I thought about it from another angle. The goal is to get to the point where it’s a 64-bit Cocoa app. All these QuickDraw calls are in the service of UI — so why not just start over with a Cocoa UI?

The app has some outlines (database browser, script editor, etc.), a basic text editor, and a handful of small dialogs. And all of that is super-easy in Cocoa.

Use an NSOutlineView, NSTextView, and some xibs for the dialogs, and we’re done. (Well, after some work, but not nearly the same amount of work as actually writing an outliner from scratch.)

In other words, instead of going from the bottom up — porting the existing source code — I decided to start from the top down.

I started a new workspace and started a new Frontier project: a Cocoa app with Swift as the default language.

Then I looked at the existing source and thought about how to organize things. I came up with this:

  • Frontier — App UI
  • UserTalk.framework — the language
  • FrontierVerbs.framework - the standard library
  • FrontierDB.framework — the object database
  • FrontierCore.framework — common utility functions and extensions

I like using frameworks, because it helps enforce separation, and it helps in doing unit testing. And frameworks are so easy with Swift these days.

Hardly any of this is filled-in yet. I’ve got the barest start on FrontierVerbs. Ted Howard, my partner in all this, is taking UserTalk.framework and FrontierDB.framework.

In the end, it’s possible that no code from the original code base survives. Which is totally fine. But it also means that this is no quick project.

At this point I should probably put it up on GitHub, since it’s easier to write about it if I can link to the code. I’ll do that soon, possibly on the weekend.

Frontier Diary #3: Built-in Verbs Configuration 13 Apr 2017, 10:25 pm

Frontier’s standard library is known as its built-in verbs. There are a number of different tables: file, clock, xml, and so on. Each contains a number of verbs: file.readWholeFile, clock.now, and so on.

Most of these verbs are implemented in C, in the kernel, rather than as scripts. At the moment, to add one of these kernel verbs, you have to jump through a few hoops: edit a resource, add an integer ID, add to a switch statement, etc. It’s a pain and is error-prone.

So I want to re-do this in Swift, because I’m all about Swift. And I want adding verbs to be fool-proof: I don’t want to remember how to configure this every single time I add a verb. Adding a verb needs to be easy.

My thinking:

  • Give each table its own class: ClockVerbs, FileVerbs, etc.
  • Have each class report the names of the verbs it supports. These need to be strings, because we get a string at runtime.
  • Run a verb simply by looking up the selector, performing it, and returning the result.

To make things easy and obvious, I think it should work like this: the selector for a given verb is its name plus a parameter. Then there’s not even a lookup step.

Each verb will take a VerbParameters object and return a VerbResult object.

dynamic func readWholeFile(_ params: VerbParameters) -> VerbResult

The flow goes like this:

  1. We have the string file.readWholeFile.
  2. We see the file suffix and so we know we need a FileVerbs object.
  3. We check fileVerbs.supportedVerbs (an array) to see if readWholeFile is in the list. It is.
  4. We construct a selector using the readWholeFile part of the string and we add a : character: NSSelectorFromString(verbName + ":")

This is great! We’re almost home free. Then we run the verb:

if let result = perform(selector, with: params) as? VerbResult {
    return result
}

That doesn’t work. We get:

Cast from 'Unmanaged<AnyObject>! to unrelated type 'VerbResult' always fails

Nuts.

* * *

It was so close.

In Objective-C this would have worked. And obviously, apparently, I still think in Objective-C.

I investigated some other options. At one point enums were abused, because there’s always, in Swift, an enum-abuse step. But everything I tried was more code and was more error-prone, and my goal here is to improve the situation.

I think, in the end, I’m going to do something that looks kind of ugly: a switch statement where the cases are string literals.

switch(verbName) {
case "readWholeFile":
    return readWholeFile(params)
…
}

“Nooooo!” you cry. I hear ya.

My experience as an object-oriented programmer tells me this: if I write a switch statement, I blew it.

And my experience as a programmer tells me that string literals are a bad idea.

But the above may actually be the easiest to configure and maintain. Each string literal appears only in that one switch statement and nowhere else in the code. And the mapping between a verb name and its function couldn’t be more clear — it’s right there.

(Yes, instead of using a string literal, I could create a String enum and switch on that. But that’s actually more code and more room for error. I’m going to have to type those string literals somewhere, so why not right where they’re used?)

It does mean that readWholeFile appears three times in the code (the string literal, the call, and the function itself), and in an Objective-C version it would appear only twice (in a supportedVerbs array and the method itself).

But. Well.

I’m torn between shuddering in abject and complete horror at this solution and thinking, “Hey, that’s pretty straightforward. Anybody could read it. Anybody could edit it.” Which was the plan all along.

And I get to stick with Swift, so there’s that.

But, sure as shootin’, some day someone’s going to come across this code and say, “Brent, dude, are ya new?” And I’ll send them the link to this page.

* * *

Update the next day: well, the performSelector thing would work, if only I’d known about Swift Unmanaged objects.

Joe Groff told me how this works.

Here’s the gist: the Unmanaged<AnyObject> just needs to be unwrapped by calling takeRetainedValue or takeUnretainedValue. Once unwrapped, it can be cast to VerbResult.

All this means that I can use my original design, which is great news.

* * *

Update April 25, 2017: I ended up using enums after all. See MathVerbs.swift for an example.

Frontier Diary #2: Two Good Ideas that Aren’t Good Anymore 11 Apr 2017, 1:01 pm

Strings in Frontier are usually either Pascal strings or Handles.

You probably don’t know what I’m talking about. I’ll explain.

Pascal Strings

Frontier is a Mac Toolbox app that’s been Carbonized just enough to run on OS X. You may recall that the Mac Toolbox was written so long ago that the original API was in Pascal. That Pascal heritage lived on in many ways, even after everyone switched to C — and one of those ways was Pascal strings.

A Pascal string is n bytes long, and the first byte specifies the length of the string, which leaves the rest of the bytes for the actual string. Str255 was probably most common, and certainly is most common in Frontier, but there are also smaller sizes: Str63 and Str31, for instance.

Unlike C strings, they’re not zero-terminated, since there’s no need to calculate the length: you always know it from that first byte.

You create a literal Pascal string like this…

Str255 s = "\pThis is a string";

…and the compiler turns the \p into the correct length (16 in this case).

Now, I bet you’re saying to yourself, “Self, those Pascal strings are too small to be useful.”

But consider this: every menu item name can fit into a Pascal string. You can fit a window title or a file name into a Pascal string (in fact, memory suggests that file names were even shorter, were Str31 Pascal strings). Any label or message on any bit of UI is probably short enough to fit into a Pascal string. (Especially if you assume English.)

So for GUI apps these were terrifically useful, and the 255-byte limit was no problem. (You can fit a tweet in a Pascal string, after all, with a bunch of room left over. [Well, depending on the size of the characters.])

Frontier still uses them internally a ton. (For some reason, in the Frontier code, Str255 strings are called bigstring, which sounds ironic, since they’re so small, but I think it was to differentiate them from even smaller Pascal strings such as Str31.)

You might ask what the text encoding was for these strings.

“Text whatzit?” I’d reply. “Oh, I see. Just regular.” (MacRoman.)

It was a good idea, but its time has come and gone. We have better strings these days.

Handles

Frontier includes a scripting language and a database, which means it certainly has a need for strings much larger than 255 bytes.

It also needs heap storage for other things — binary data, structs, etc. — that could be much larger than 255 bytes.

Enter the Handle. A Handle points to a pointer that might move: the memory you access via a Handle is relocatable.

Which sounds awful, I know, but it was a smart optimization in the days when your Mac’s memory would be a single-digit number of megabytes, or even less than that.

Here’s the problem: your application’s heap space can become fragmented. It could have a whole bunch of gaps in it after a while. So, to regain that memory, the system could compact the heap — it would remove those gaps, which means relocating the memory pointed to via a Handle.

This is better than running out of memory, obviously. But it means that you have to be careful when dereferencing a Handle: you have to actually lock it first — HLock(h) — so that it can’t be moved while you’re using it. (And then you unlock it — HUnlock(h) — when finished.)

Handles are also resizable — SetHandleSize(h, size) — and resizing a Handle can result in it needing to move, if there’s not enough space where it is. Or other Handles might move. You don’t ever know, and don’t care, and you think this is elegant because the system handles it all for you.

All you have to deal with is an additional level of indirection (**h instead of *p), locking and unlocking it when needed, and disposing of it — DisposeHandle(h) — when finished. (No, there’s no reference counting, slacker.)

Nowadays, on OS X, Handles don’t ever move and there’s no heap compaction. So there’s no reason for them whatsoever. And they are, as expected, deprecated.

Nevertheless, Frontier, a Mac Toolbox app written in C, uses Handles everywhere.

(I remember being shocked, when I first started learning Cocoa 15 years ago, that there were no Handles. It seemed incredibly daring that objects were just pointers. It made me nervous!)

The Size of the Job

Almost all the Mac APIs that Frontier uses are deprecated. That’s one thing.

But it’s worse than just that: the ways Frontier handles strings and pretty much every single thing it stores on the heap are also deprecated.

So: what to do?

The end goal is a Cocoa app, which means I’ll be able to use Foundation, CoreFoundation, and Swift data types: NSString and Swift String, for instance. There are a number of different structs in the code, and those will be turned into Objective-C and Swift objects and Swift structs.

The tricky part, though, is getting from here to there. I think the first step is to start with Objective-C and Foundation types and use them where possible. I can do that without actually turning it into a Cocoa app (the app will still have its own WaitNextEvent event loop and Carbon windows) — which means I’ll have to bracket all Objective-C code in autorelease pools, and I’ll have to use manual retains and releases. I’m not sure how far that will get me, but it will get me closer.

PS Here are a couple articles by Gwynne Raskind on the Mac Toolbox you might enjoy: Friday Q&A 2012-01-13: The Mac Toolbox and The Mac Toolbox: Followup.

Two Little-Known and Completely Unrelated Facts 5 Apr 2017, 4:57 pm

One. OmniOutliner’s outline view is implemented as CALayers rather than as a view with subviews. (I don’t think I’m giving away a trade secret here.)

Two. If you eat fenugreek, your armpits will smell like maple syrup.

iOS, JavaScript, and Object Hierarchies 5 Apr 2017, 2:53 pm

Rob Fahrni:

Given x-callback-url and App URL schemes in general it would be extremely cool to use those to create object hierarchies using JavaScript. Why JavaScript? Well, it’s native to iOS and applications can use the runtime.

CocoaConf Near WWDC 5 Apr 2017, 2:35 pm

There are a bunch of things happening near WWDC this year. Me, I’ll be at CocoaConf Next Door. I’m not preparing a talk, but I’ll probably be on a panel. And hanging out.

Check out the speakers list, which includes Omni’s own Liz Marley. And a bunch of other people you totally want to see — Manton Reece, Jean MacDonald, Laura Savino, and plenty more.

Also… AltConf and Layers will be near WWDC. If you could be in three places at once, you would. Well, four, including WWDC itself, I suppose. :)

OmniOutliner 5.0 for Mac 5 Apr 2017, 10:44 am

I’ve been on the OmniOutliner team for over a year now. Though we don’t have positions like junior and senior developer, I enjoy calling myself the junior developer on the Outliner team, since I’m newest.

I may be a new developer, but I’m not a new user — I’ve been using the app since the days when OmniOutliner 3 came installed on every Mac.

Every time I start a talk, I outline it first. I organize the work I need to do in my side-project apps in OmniOutliner. And — don’t tell the OmniFocus guys, who are literally right here — sometimes I even use it for to-do management in general. I’d be lost without a great outliner.

Anyway… there’s a new version: OmniOutliner 5.0. It’s my first dot-oh release at Omni, and I’m proud of it and proud of the team.

As is common with our apps, we have two levels: a regular level and a Pro level. The regular level is called “Essentials” and is just $9.99. There’s a demo so you can try it out first.

It syncs with iOS and with other Macs, by the way. Sync is free. And of course it comes with extensive documentation, and Omni’s awesome support humans are standing by.

Get it while it’s hot!

Page processed in 0.299 seconds.

Powered by SimplePie 1.3.1, Build 20170724043435. Run the SimplePie Compatibility Test. SimplePie is © 2004–2017, Ryan Parman and Geoffrey Sneddon, and licensed under the BSD License.

©©