434 karma · joined February 3, 2013
First-class procedures/functions are a form of composition. Requiring a function type behaves like requiring an interface/class type with only one method. (In languages like F#, `Func<_,_>` is literally defined internally as an abstract class with one method, `Invoke`, although there are other mechanisms to auto-inline lambdas when enough static information is available to do so.) In either case, you can place it into a field of an object or data structure, or pass it directly as an argument to a function/method.
There were rumblings that my high school, which had plenty of AP classes already, was about to introduce a combination AP/IB curriculum, which absolutely terrified us. I and my AP-taking classmates breathed a huge sigh of relief when it was announced that it would be delayed, and the students in the year below us would be the guinea pigs. They would have to run twice as fast just to stay in place.
(The film "Force of Evil" is about a plot to nevertheless rig the outcome.)
It's uncharitable to take Casey as making absolute blanket statements like that, but still, it would not be unreasonable for him to single out Uncle Bob in particular.
The Amazon rankings for Bob Martin's "Clean Code":
Best Sellers Rank: #5,338 in Books (See Top 100 in Books)
#1 in Software Design & Engineering
#2 in Software Testing
#4 in Software Development (Books)
For one thing, sketching out variations on a design typically reveals there's a wide space of possible parameters in the spec. In many cases it's obvious that only a small subset will actually be technically feasible (either for machining or for reasonable functionality of the finished artifact or both), but not obvious exactly what that subset will be.
I'm not even talking about what could be revealed by finite element analysis or other formal methods (though I'm not averse to learning those too). I mean the feel, the taste, and the intuition I can't get from just drawing and doing the math. Like Jackie Stewart said, "You don't have to be an engineer to be be a racing driver, but you do have to have Mechanical Sympathy." I have mechanical sympathy for computing systems, for rapidly narrowing down appropriate design spaces in software projects, but I don't yet have mechanical sympathy for mechanical systems.
It's tough to plan a path toward growth in these skills without sustaining inordinate expenses at each step. I can't afford to become afflicted with Gear Acquisition Syndrome. I've come close to dropping huge sums of cash on tools before discovering, at the last minute, critical reasons that they could not do what I need for the designs I have in mind. Maybe I'll visit a makerspace? Ah, but every one in my area appears to have gone defunct since Covid year zero.
So the journey up to this point has been:
- A lot of reading: not just faffing around with hobbyist blogspam -- full-on MechE textbooks, learning what really goes into engineering schematic diagrams, all that good stuff
- Getting back up to speed with the pencil-on-paper geometry and math skills I've lost after years of doing all my intellectual work in digital form (at least I can still draw a freehand circle)
- Proto-proto-prototyping: just making some physical objects roughly of the same geometry as what I've designed -- whittling them out of wood, sculpting them out of polymer clay
- Hacking together janky tools: trying to make a crappy mini lathe out of Meccano-clone parts, trying to make a crappy mini lathe out of an electric drill, just to get a basic feel for what's involved
- Apologizing to my wife for all this weird scary stuff in the corner of the apartment
I was a CS major. The only hands-on physical engineering I did in college was cooking a single-transistor chip in a freshman applied physics lab. Basically I feel like someone who has studied everything about the physics of bicycles but has never ridden one. I'm really struggling on how to proceed.
But the content more than makes up for the style!
Think about all the places you've ever worked, all the organizations you've been part of, where you know how the sausage is actually made, and how that differs from the way the organization portrays itself.
Now think about all the other organizations in the world, whose internal workings you're not privy to.
- Triviality
The most trivial cases are actually the most important. If I build a little DSL, I give it an explicit "identity" construction in the internal representation, and use it liberally in the implementation, transformation phases, and tests, even though obviously its denotation as a no-op will be optimized away by my little DSL compiler, and it may not even be exposed as an atomic construct in the user-facing representation.
- Free constructions
When it's difficult to separate a model from an implementation, when simple interfaces are not enough because the model and implementation are substantially complex, multilayered systems on their own, often the answer is to use a free construction.
Free constructions are a killer tool for allowing the late-binding of rather complex concerns, while allowing for reasoning, transformation, and testing of the underlying components without worrying about that late-bound behavior. "Late-bound" here does not have to mean OO-style dynamic dispatch -- in fact now you have more expressive power to fuse some behaviors together in a staged manner with no runtime indirection, or to make other behaviors legitimately dynamic, differing from one call to the next. Tradeoffs in the flexibility/performance space are easier to make, to change, and to self-document.
This is particularly useful when you need to start addressing "meta" concerns as actual user-facing concerns -- when your project matures from a simple application that does Foo into a suite of tools for manipulating and reasoning about Foo and Fooness. Your Foo engine currently just does Foo, but now you want it to not just do Foo, but return a description of all the sub-Foo tasks it performed -- but only if the configuration has requested those details, because sometimes the user just wants to Foo. So you embed the basic, non-meta-level entities representing the actual component tasks in a free construction, compose them within that free construction, and implement the configurable details of that composition elsewhere.
- "Sameness"
Making clear distinctions between different notions of sameness is important. Identity, equality, isomorphism, adjointness -- sure, you might never explicitly implement an adjunction, but these are important notions to keep separate, at least conceptually if not concretely in source code entities, as a piece of software grows more complex. If you treat two things as fundamentally the same in more ways than they really are, you reach a point where you now can no longer recover crucial information in a later phase of computation. In an indexed/fibered construction, this X may be basically the same as that X, but this X, viewed as the image of a transformation applied to Y is quite different from that X, viewed as the image of a transformation applied to Z, although the images are equal. So can I just pass my X's around everywhere, or do I need to pass or at least store somewhere the references to Y and Z? What if computationally I can only get an X as the result of applying a function to Y, but conceptually the functional dependency (that is, as a mathematical function) points the other way around, from X to Y? Paying attention to these easy-to-miss distinctions can save you from code-architecting yourself into a corner. You may discover that the true reserve currency of the problem domain is Y when it looks like X, or vice versa.
"As a result of having only conventions, there is no strong insurance against a developer using the dependencies directly, instead of going through the ports, or adding a new dependencies without the associated port (it happens, we all have seen it)."
As long as you have some of the same developers working on multiple layers of the application's architecture, it's easy to accidentally reintroduce violations of the layer boundaries, even if you originally wrote the application using clean, well-designed interfaces.
Say project Layer2Implementation depends on project Layer1Interface, as it should, but also depends on Layer1Implementation, possibly due to a transitive dependency that's not immediately obvious. But the build system and IDE know the project dependency is there, and now it's all too easy to refer to a Layer1Implementation internal helper function or have one suggested to you via autocomplete, even if you didn't include it in your top-of-file "open" declarations. And because you were just fixing up something else in Layer 1 an hour ago, you think to yourself "aha, I know that function, it's useful!" and plug it right in to your new Layer 2 code.
This may be why some languages are so anal about requiring explicit public/private/internal accessibility modifiers on everything, but those are highly susceptible to code rot anyway. First the real conceptual interface ends up scattered among a bunch of different files. Then under time pressure, more and more things get mindlessly marked public just so a developer can get a feature into an easily testable state. Module interface files are a pain too if they're optional (as in, say, F#).
You really want to have one tangible, named entity that groups together the functionality you actually want to expose to other layers. You want to make it impossible to refer to things you shouldn't be referring to, without making accessibility hygiene a maintenance burden in its own right. I feel like ML-style modules and abstract data types are great for this, although I've never written a sizable application in any ML dialect. The new static interface stuff in .Net is a nice step in that direction though.
The web site and order system is in German, but I've been able to talk to their friendly customer service in English. Then there's the matter of shipping outside of Europe... but it's still much easier than scraping parts together from vintage Meccano vendors with circa-1995-style web sites.
I remember having some Erector sets as a kid in the '90s (they had merged with Meccano long before, and the choice of which brand to appear on which set seems to have been random since then), but these days the official Meccano/Erector selection is almost non-existent -- there are maybe a dozen small self-contained model vehicle kits, and you can't order generic kits or parts in bulk. It is rather sad -- these brands were once used for serious engineering prototyping and scientific work: https://en.wikipedia.org/wiki/Differential_analyser#Use_of_M...
The rankings are probably more meaningful at the bottom of the list than the top.
Here's a transcript of what I can decipher from the robot voice:
--------------
(WARNING: PRETENTIOUSNESS)
While concentrating on complex tasks or creative work, we often feed ourselves streams of musical information in an attempt to occupy the parts of our minds that would otherwise be left relatively idle.
Without this, under prolonged periods of concentration, those other active brain centers create a sense of imbalance. It can often create distracting interjections from powerfully oblique thoughts about food, memories, desires, and emotions.
Using music in this way is nothing new, but for the wrong choices we can often find ourselves fighting against thematic intent to such a degree as to almost denigrate the music itself. We train ourselves to tune out ??? what we've chosen to be background noise.
The goal of this series is to provide listening experiences that can be fully appreciated for their artistic intent despite sometimes having only partial attention paid to them. That is not to say that the music is not worthy of exclusive attention, but that it contains themes or textures of a certain type that the problem solving brain centers won't have trouble processing and fully appreciating while attempting to code, write, or draw.
In other words, the music itself should not task the listener with too much problem solving ???. The musical ideas developed will cover large thematic and emotional distances, but rarely in such a short space of time as to sound dramatic. The back-and-forth motion between contemplation of the next stage of your work and the subsequent actions to realize it will necessarily create peaks and troughs in brain activity.
This series attempts to provide a soundtrack that can be fully appreciated at the level of entire ???. More importantly, the episodes have been lovingly crafted by people who have invested huge chunks of their lives finding all this beautiful stuff ???.
"*n [stringA] "*n
"*n [stringB] '*n
'*n [stringC] "*n
'*n [stringD] '*n
Each string may contain runs of contiguous single or double quotes of length less than n, and furthermore:stringA may start and/or end with a single quote
stringB may start with a single quote and/or end with a double quote
stringC may start with a double quote and/or end with a single quote
stringD may start and/or end with a double quote
It shows that you can implement algorithms that give the same results as MLsub without following the algebra so closely, but those algorithms were still designed with MLsub as a reference. It would be difficult to just stumble on a system like Simple-sub without that guidance.
And Dolan's emphasis on the algebra of types still provides a guiding perspective for future work. If you want to add subtyping to a language with a more sophisticated type system, or add new features to a language that already has subtyping -- even if the existing subtyping system was written using MLsub or Simple-sub as a starting point -- you should probably take a long hard look at it from an algebraic point of view to make sure they interact the way you want, rather than call it a day after finding the simplest way to add the feature while still yielding a type lattice.
Not only that, Yang ran a couple of UBI-themed contests offering a chance to win money for following and retweeting him. What better use is there for acquiring an army of fake accounts?
I realize this sort of contradicts my other comment, but I want to believe I didn't spend all those years as a music geek for nothing!