joe-user
Joined 10 years ago
Joined 10 years ago
CHERI has different characteristics in that it will crash for buffer overflows, but crashing on use-after-free is opt-in, it can only detect double-frees sometimes, it does nothing about uninitialized memory access, etc. It also requires adopting new hardware, which may be a hard sell.
In all I've mentioned above, I haven't even touched thread safety or integer safety which these do nothing about.
So with that being said, do as you please, but understand that simply adopting these is a different level of safety (program will not be exploitable but will crash) compared to something like Rust (program is not exploitable and will not crash because these issues are mostly* compile-time errors).
* "Mostly" since I mentioned integer safety which will be a runtime crash like the C safeguards, you can use unsafe, etc.
Perhaps not what you intended, but I believe this is that exactly what Cosmopolitan is doing: - They are writing portable software in that it can run on various architectures and operating systems - They compile it for each platform, even if the output is a single binary - For the best performance and functionality, they mention several examples of how Cosmopolitan outperforms the native alternatives
I'm sure there are plenty of rebuttals ("Emacs on Windows is a port", "Cygwin isn't portable", "they could make the native version of $WHATEVER more performant", "Cosmopolitan isn't always faster", etc.), all of which are well and good, but would be missing the bigger picture, which is that there are reasons for both approaches (among others!) to exist, an idea that far transcends software.
You mentioned moving JOINs around, so I'll mention that if represented as structured data, you can move any of the top level components around, so you could more closely follow the "true order of SQL" [1]. For example, I would love to be able to put FROM before SELECT in all or almost all cases. There's also being able to share and add to something like a complicated WHERE clause, where essentially all programming languages have built-in facilities for robustly manipulating ordered and associative data compared to string manipulation, which is not well-suited for the task.
Now don't get me wrong, I don't particularly care for YAML (though it doesn't bother me that much), but as someone who's done their fair share of programmatic SQL creation and manipulation in strings, not having a native way to represent SQL as data is a mistake in my opinion.
0: https://github.com/seancorfield/honeysql#big-complicated-exa... 1: https://blog.jooq.org/a-beginners-guide-to-the-true-order-of...
Also, although it may not be easy to remember, is this really a problem in practice given the installation count in most contexts is one? If there's a context where it's installed regularly, that's a one-time addition to an install script, Dockerfile, etc. in my experience. Do you have a situation that isn't amenable to that?
> 99% of top Python packages are now on version 2
I think judging only from what you saw there is the issue. If you look somewhere like Wikipedia [0], you'll see he was the first person to jailbreak the iPhone, the first person to achieve hypervisor access to the PS3's CPU, he took first place in several notable CTFs (at least one time as a one-person team), he worked on Google's Project Zero team (and created a debugger called QIRA while he was there), creating comma.ai, and the list goes on.
As someone who writes more Python than Clojure these days, Python's limited lambdas are a regular source of frustration. Additionally, Clojure's first-class data structures are sorely missed in Python.
> 2. REPL-driven development!
The huge drawback IMHO that rarely gets discussed is the ability to change modules in Python's interactive interpreter (Clojure's analog is the namespace). For example, in the context of a web app, adding a new view in some views module, then swapping to the routes module and adding the adding a new route to wire up the view. Additionally, there's no built-in way to connect to the interpreter, as manually typing in a REPL is not the usual flow. To me this makes Python's interpreter unusable for anything but toy examples.
> 3. Macros!
Clojure is less macro-dependent than other lisps, but in most projects I use, there are one or two that really help clean things up. If you look to other modern languages that have macros (for example, Rust), I think the same idea applies.
I've added Clojure to several legacy Spring Boot apps, and the fact that it can be introduced as "just a library" made that portion a snap. If you're not trying to access resources related to Spring Boot's dependency injection, it's pretty straightforward to call into Clojure from Java. If you _do_ want access to DI resources, there's a small amount of code required to wire things up, though it took me a while to find out what that code was, mostly because it requires access to portions of Spring Boot that are not typically user-facing.
Since I had hooked Clojure up to the Spring apps, I also set things up so I could SSH onto application servers, then get a REPL via a socket server into the applications themselves. Being able to check and sometimes change the state of the application live at runtime was like a superpower. This proved extremely valuable, often for debugging errors in the Java portions of the code, but also for situations like final design tweaks live with a client in a development environment. Client asks to bump a font size or change a color or adjust a border or change some copy, then I make the change in my editor, send it over the socket REPL, tell the client to refresh, and repeat. When done, I would simply save, commit, and would be confident that it's what the client was after. The only downside is that I'm no longer at a shop that uses Clojure, and feedback loops for production debugging or letting clients see their decisions are measured in days or weeks when possible at all, not seconds or minutes.
I will admit that connecting to a running application is dangerous, but so is what many surgeons do, and we are certainly not going to ask them to turn in their scalpels. By being conscious of the "great power; great responsibility" bit, I was able to come out mishap-free.
On the other hand, when I had to create new projects where I thought Clojure would be a good fit, I just went all-in with the Clojure ecosystem rather than start with Spring Boot and add Clojure, and I found going all-in with Clojure to be incredibly productive. With that being said, I made the decisions with a decent understanding of both Spring Boot and Clojure, so my experience would likely vary from that of someone who is experienced with Spring Boot and knows nothing of Clojure.
I was curious about this as well, and the answer was "no". I meticulously followed EAC setup guides for three drives in EAC, I used the recommended gap settings, the results were completely verified by AccurateRip, I was storing the results as a CUE sheet and single WAVE file, all drives would produce the same file, I was using EAC to burn the CUE sheet and WAVE file back to new Verbatim CD-Rs, re-ripping was done with the same setup in EAC, and the files still didn't match. I've been meaning to dig deeper and compare the files in binary, but haven't gotten around to it.
Your comment:
> Safari is so behind in terms of lack of support for free media formats/codecs like webm, webp, and av1. You can't even switch browsers to view them, since it's all webkit
Maybe you do keep up with this stuff, and you did say they are so behind, but you also said "You can't even switch browsers to view them", which is not true.
This is also where tests shine, which are far more expressive than the type systems we have today. Tests are usually not as convenient as types though, but it's another parameter to consider when choosing the right solution for a given scenario.
> But I will not give up that ability to make a refactor in core code and then turn be able to address all of the places that that change breaks things.
This will be less satisfying since it's anecdotal, but I'll offer up my experience anyhow: I rarely find myself refactoring. When I do refactor, it's almost always in the "changing the factoring" sense, in that callers are none the wiser to changes since the interface is the same, which limits the fear of breakage. That's not to say that it always turns out this way, but churning regularly on interface boundaries would be a "smell" to me.
To further beat the drum from above, I'd additionally expect the tests to help prevent breakage whether the program's dynamically or statically-typed. I review plenty of code, much of it in Scala, which puts a heavy emphasis on its strong typing. When there aren't tests, I request them or write them myself, and that uncovers bugs more often than not despite the programs passing the type checker.