Progress on supporting a subset of Markdown in my ...
# two-minute-week
k
Progress on supporting a subset of Markdown in my text-mode paginator, and how programming languages can use modules without explicitly importing them. https://archive.org/details/akkartik-2min-2020-06-07
💡 1
👍 2
s
The algorithm you use to determine the types is interesting. Did you come up with that yourself? Or do you have any pointers to what inspired you? I‘m also curious how you settled on Markdown parsing for the demo? I‘m strangely attracted to Markdown for a prototype as well.
👍 1
k
I'm basically noodling on what a simpler world wide web looks like, where we only use browsers for reading and hyperlinking, not for web apps. The only reason there was a demand for sandboxed web apps historically was that native apps on PCs had so thoroughly polluted the well for users. But in a world where apps are always distributed with source and there's a culture of calling folks out for dark patterns, you don't need the web to run apps anymore. My ideas here are a lot less well-formed than for the foundations of Mu, so I'm extremely open to suggestions. Markdown's just the first syntax I tried to avoid designing a 15th standard. Though I'm already seeing crap I'm never going to support, like this:
Copy code
This is *emphasized
# text.* Or is it?
Things are simpler if I require headings to always start a new paragraph. --- I came up with the algorithm myself, but it felt like a fairly straightforward multi-pass compiler design. The only minor issue was the chicken-and-egg problem of needing sizes to compute field offsets, and needing field offsets to compute sizes. I'm not well-versed with the theory of Algorithms so I can't cite good keywords here. But I think a lot of people would be able to come up with it after completing a grad course in compilers. Once the problem was framed.
🍰 1
s
Yeah, there are some weird edge cases in Markdown. I'm all for a simpler standard and would be happy to break backwards compatibility, getting rid of some of those weird edge cases. Complexity of implementation is particularly important for standards where we hope to see many implementations, but hardly ever considered. We learn so much from implementing a thing, but we tend to only practice additive design, cramming more things into it over time. Maybe that is the nature of things. At some point more people feel that the old thing is now bloated and that opens the door for another, better designed, simpler thing to take over. Somewhat the story of Mu, I guess… ;)
❤️ 2
i
Definitions appearing after usage reminds me a bit of the original literate programming, where it's important that the source code be free to occur in whatever order best fit the explanation around it. How does your approach to out-of-order compilation interact with other language features, like error handling or polymorphism or extension (if you have those)? Eg: what happens if you've used a field that doesn't appear in the type definition? How do you do namespacing without modules?
❤️ 1
(I imagine some of these questions are irrelevant given the design of Mu, but I don't know enough about the design of Mu to know that I'm being a total noob about it :P)
k
Yeah, Mu doesn't have namespaces, anything dynamic like
method_missing
(did I understand "error handling" right?) or open types. It's fairly unambitious as a language; all the attention has gone to bootstrapping the implementation out of machine code. But your concrete question is quite acute. "What happens if you've used a field that doesn't appear in the type definition?" I hadn't thought of it yet when I made the video. It only occurred to me in the past week. I now raise an error if a type definition failed to reconcile some field from earlier. But it's a fairly klunky error message; it just says, "you used field
x
but it doesn't exist." It can't give the line or even function that used
x
. Providing such errors is going to complicate the implementation quite a bit, needing to attach source info to uses of fields in types. But I did stake out a position in my paper as being all about the quality of error messages. This whole thing is now making me quite unhappy. Perhaps I'll toss out this flexibility after all. Funny story: the previous prototype of Mu (a tree-walking interpreter) did have support for literate programming. (And function overloading, and generics, none of which are in the current prototype.) I hadn't connected the dots to think of this as a particularly Literate feature. That might be a good justification to take it out. Thanks! _The reason Mu doesn't have LP anymore_: I was fine encouraging hunks to refer to local variables that were in the same scope but far away in some other part of the description. However, the way Mu now exposes and requires using registers, hunks can now destroy local variables far away in the same scope (that happen to share the same register). That feels too mind-bending. Then again, maybe I should allow shadowing. So you can't insert naked statements using Literate directives, only blocks. Hmm, that could work. (If I can get the error messages good enough.) Thanks!
I'm growing aware of a major inconsistency in my belief system. On the one hand I'm constantly pushing for programs in a system to be aware of their dependencies. However, I also dislike modules and namespaces and the need in general to micromanage dependencies in the small within a single program, to manually provide information that a compiler could just deduce. Perhaps this is a contradiction, and I need to give up opinions that made sense in the context of a highly dynamic, high-level, expressive Lisp dialect. Perhaps a low-level language built in machine code should throw up its hands and require the programmer to do a little more work. On the other hand, perhaps this is a paradox, and what the two positions share is a desire for parsimonious dependencies. Tools to specify dependencies within a project tend to encourage larger projects with more code. Mu lacks modules for the same reason Mu lacks packages and will never have a package manager. Reader, please let the author know what you think of this precious-snowflake navel-gazing.
i
I hadn't connected the dots to think of this as a particularly Literate feature. That might be a good justification to take it out. Thanks!
You troll!
Reader, please let the author know what you think of this precious-snowflake navel-gazing.
I think you have some tough decisions ahead of you.
Then again, maybe I should allow shadowing.
Is Mu aimed at beginners? If so, be careful about shadowing. In my experience every new programmer steps on that nail, and I've known some who were then scared away from taking advantage of it for evermore. (Example of the nail: top-level variables can be shadowed, struct members can't, but you often assign to both in the same way.)
Perhaps a low-level language built in machine code should throw up its hands and require the programmer to do a little more work.
That could be a worthwhile bunt for the time being, and you could come back to this in the future.
👍 1
k
I'd almost made up my mind in the same direction. Then I remembered that I plan a type-checking pass anyway. It'll be some redundant work then, but not more complex. Best of both worlds. All problems can be solved with an extra pass.
Still no Literate Programming 👍 Mu does have shadowing, though. Your example of struct members is interesting 🤔
i
That shadow-nail example just another incarnation of references vs values.
Copy code
top level
a = 5
b = a
a = 6
wtf is b?

struct
a = {x: 5}
b = a
a.x = 6
wft is b?

shadowing
a = 5
{
  a = 6
}
wtf is a?
k
Maybe I'll disallow reusing the same variable name. Really I only need shadowing for reusing registers.
Update: I didn't do much this week due to RSI, but I've fixed the problem of "What happens if you've used a field that doesn't appear in the type definition?"
❤️ 1
i
I feel you. Hands?
k
Yeah..