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 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. :)
* * *
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.
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).
Plus I think you’ll enjoy it. :)
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:
One of the more serious criticisms was this: why not just support the hAtom microformat instead? Why do another side-file?
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.
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.
* * *
I think I have three options:
- Go down the rabbit hole of figuring out how to get the parser to work with ARC.
- 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
CodeTreeNodeobjects, and then disposes the C-struct-node-tree.
- Write the parser by hand, in Swift.
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.
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.
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.
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.
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:
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 (
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.
This means passing around an actual
Bool rather than a boxed boolean. I like this a ton. It feels totally right.
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.
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.)
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.