I use those tools nearly every day. Instead of heavy LSPs and IDEs using the RAM that could be otherwise used, I grep and ctags through my codebase for instant navigation. For deterministic changes if I haven’t already done it in vim, I awk and sed, though usually I do buffer-wide changes in vim for such things. When troubleshooting CLI outputs, especially for binutils and other tools I didn’t write, I still use combinations of awk, sed, and grep.
Not everything is thrown together code churn. Some tools have earned their keep and don’t need to be in the constant spotlight because they do their job silently and effectively for people such as myself on a daily basis.
The issue with all of these schemes is less about the format and more about the semantics itself. What are all the actions that can be done to a codebase and what is a controlled vocabulary that encapsulates those? Then it doesn’t matter what system you use.
I spent some time recently coming to the conclusion that I did not prefer CC, but wanting some reliable structure. In the end, I found I was coming up with convoluted schemes that were getting in the way of actually solving my real problems and just settled on the tried and true:
“When applied this commit will...”
- Add <functionality>
- Update <existing>
- Refactor <while keeping same boundary behavior>
- Remove <some subsystem or functionality>
- Cleanup <documentation or style>
I don’t consider this to be a complete taxonomy, but it does let me get on with my day and covers most things, especially when combined with thoughtful commit messages.
You should look into `update-refs` functionality. By default git treats each branch independently, but with update-refs, git tracks pointers to branches and creates a dependency chain.
I’m fairly certain that the difference between the approaches is that the f(x,y) function you mentioned requires limits to represent certain concepts while the eml approach is essentially a tree or a chain of computations meant to represent a model of a system.
They're not series, that's just a convenient way to think about defining and calculating them. I've never found it particularly useful to deal with the series definitions either, and none of the (good) approximation methods I'm aware of actually take that approach.
Moreover, EML is complete in a way that your suggested function isn't: If you take a finite combination of basis functions, can it build periodic functions? Hardy proved over a century ago that real (+,-,/,*,exp,ln) can't do this (and answering the paper's unresolved question about similar real-valued functions in the negative). EML being able to build periodic functions is a lot less surprising for obvious reasons, but still pretty neat.
EML goes through complex numbers and infinities internally.
Previous commenter meant that there are infinite series inside log and exp.
To achieve a thing like sin(x) from his universal expression, yes you'd need infinite series of those, not a finite set of operations, but to get all 36 basic function you'd need a finite set of different infinite series.
So exp and log just happen to be the labels for two element set of such infinite series that you'd have to use to make 36 functions out of the operator that pervious commenter proposed.
All that said, I still think it's pretty neat too.
I understand your point. The paper is more about the depth of the tree to represent and audit a model versus the raw CPU clock cycles. It takes the exponent and logarithm as given since for all practical purposes, in a scientific context, they are.
To represent something like sin(x) with f(x,y) requires infinite steps. Conversely, with eml you get an exact result in around 4 using identities and such.
One could argue that we do Taylor Series approximations on the hardware to represent trigonometric functions, but that highlights the key aspect of the eml approach. You can write a paper with those four steps that describes an exact model, here sin(x). And people can take that paper and optimize the result.
This paper is about an auditable grammar that you can compute with.
You can reduce all Boolean logic to NAND, but that doesn't actually mean that semiconductor fabs translate their HDL to NAND gates, because it is possible to build complex gates that directly implement higher level operations in a single gate.
Your "cost of computation" objection can be easily resolved by adding more operators, which makes it boring from a research perspective.
Meanwhile the loss of expressivity can only be compensated by encoding algorithms directly into the expression tree. Your objection that an infinite series is a bad thing rings hollow, since you now introduce the concept of an infinitely sized expression tree. That sounds much more impractical than implementing an algorithm for the exponential and logarithm functions.
Show me a way to physically compute exp or ln that is less gates than add. More gates means costlier in $, more energy in compute, and for these functions, higher latency.
You don’t get to make up free ops, claim there is no cost in reality, and hand wave away reality.
There are infinitely many ways to do what the paper did. There’s no gain other than it’s pretty. It loses on every practical front to simply using current ops and architectures.
Conceptual elegance is worth something, isn't it? I don't mean just aesthetic pleasure, as in recreational mathematics, but there's often (not always) value in being able to succinctly describe a wide range of phenomena with a small number of primitives. It could open up new ways of understanding or working that wasn't possible before. Not saying this specific discovery fits the description, but it seems too early to dismiss the idea entirely based on its im/practicality compared to existing solutions.
Aren't there examples in the history of mathematics, where a new idea was criticized for being impractical, then later found to have applications or implications, possibly unexpected even to the person who discovered it?
I feel sad when pragmatics comes in scientific discussions... that's not what science should be (I think).
But I value the discussion this paper is bringing to distinct contexts (even outside academia). That by itself adds value to this work.
No, it approximates exp poorly over an infinitesimally small interval compared to exp. Resistors and capacitors are no where ideal components, which is why they have spec sheets to show how quickly they diverge.
If we’re making sloppy approximations to a tiny range of exp, then I too can do it with a few terms.
The feasibility of memristor analog circuits is evident, and I believe this paper represents a valuable early exploration. We've been constrained by Boolean logic for quite some time now.
The world has had many types of logic before and after Boolean logic was created, many used in computing. Boolean logic isn’t a constraint; it’s used where it’s useful, and others are used where they’re useful.
> Prefer do notation if the effects of the flow are more important than the data structure, and prefer using Applicative style if the data structure layout is more important to understand than the effects to build i.
See vim-mergetool[1]. I use it to manage merge conflicts and it's quite intuitive. I've resolved conflicts that other people didn't even want to touch.
It would be nice if specific offending portions of the codebase were highlighted. As of now, it’s hard to see why one should use this fork. Also, since the source is available, anyone can just compile a past version of vim.
Agreed. Without the context it just feels like a petty reaction. For all the reader knows, it could be completely unrelated to AI. The repository owner could’ve had a falling out with the maintainers regarding features or may be trying to inject their own malicious code into the fork.
A cursory search didn't turn anything up in the vim repo or elsewhere. I can see why the authors of the fork wouldn't want to stir up drama, but I am really curious too.
It’s not about specific offending portions, it’s the principle of having any LLM contributions at all. There’s a group of people who are so opposed to this stuff that they object to its mere presence anywhere.
The issue with that stance, practically speaking, is that anyone could have hand-submitted generated code at any time, so why this January cutoff date?
I would expect a decrease in code quality in a specific part of the repo or at least a quote/link to a changelog stating that generated code is being used as part of the fork making its case.
They're already talking about pushing it back farther, trying to revert/rewrite every commit from users suspected of ever using LLMs. Practicality doesn't really enter into it, this is an ideologically driven project that insists on getting rid of the "taint." https://codeberg.org/NerdNextDoor/evi/issues/19
I understand it is an ideological project. My point is that given their intent, there are things they should do to make their case. They should provide the evidence in the README etc.
If they are correct and things must be done, they aren’t providing the evidence. That’s not the same as saying there’s no evidence or reason to take this stance. Do you see the distinction I am making?
Are you talking about evidence that LLM contributions are harmful, or evidence that there are any? The former is unnecessary, as this is not an evangelism project, it's for people who already believe LLMs are bad. For the latter, I think the project is aimed at people who are already plugged into the issue, or suffers from the usual mistake of thinking everyone is plugged into a specific issue. In any case, it takes about five seconds to search for "claude" in the main vim repo's PRs and find that evidence.
The challenge for most people is that HTML and Modern CSS are a declarative programming paradigm. You then selectively sprinkle state on top of that.
I use HTML and Modern CSS for frontend. I sprinkle htmx when I want interactivity and a tiny amount of plain JavaScript. That gives me a mostly declarative frontend.
On the backend I use Haskell, which is also declarative unless you opt into other things.
The challenge with web development is that we’ve learned over the years that asynchronous, stateful programming is the most bug-prone programming yet we reach for it first. We should reach for those things last and where they are appropriate.
The thing about cascading style sheets is that it all cascades by default. A web page naturally resizes. It’s when we add all this other stuff that things start breaking and becoming rigid. The key to CSS is knowing when to let go.
Earlier in my career, I found that my employers would often not buy Matlab licenses, or would make everyone share even when it was a resource needed daily by everyone. Not having access to the closed-source, proprietary tool hurt my ability to be effective. So I started doing my "whiteboard coding" in Julia and still do.
Precisely; today Julia already solves many of those problems.
It also removes many of Matlab's footguns like `[1,2,3] + [4;5;6]`, or also `diag(rand(m,n))` doing two different things depending on whether m or n are 1.
An understated advantage of Julia over MATLAB is the use of brackets over parentheses for array slicing, which improves readability even further.
The most cogent argument for the use of parentheses for array slicing (which derives from Fortran, another language that I love) is that it can be thought of as a lookup table, but in practice it's useful to immediately identify if you are calling a function or slicing an array.
I don't think Julia really solves any problems that aren't already solved by Python. Python is sometimes slower (hot loops), but for that you have Numba. And if something is truly performance critical, it should be written or rewritten in C++ anyway.
But Julia also introduces new problems, such as JIT warmup (so it's not really suitable for scripting) and is still not considered trustworthy:
> Python is sometimes slower (hot loops), but for that you have Numba
This is a huge understatement. At the hedge fund I work at, I learned Julia by porting a heavily optimized Python pipeline. Hundreds of hours had gone into the Python version – it was essentially entirely glue code over C.
In about two weeks of learning Julia, I ported the pipeline and got it 14x faster. This was worth multiple senior FTE salaries. With the same amount of effort, my coworkers – who are much better engineers than I am – had not managed to get any significant part of the pipeline onto Numba.
> And if something is truly performance critical, it should be written or rewritten in C++ anyway.
Part of our interview process is a take-home where we ask candidates to build the fastest version of a pipeline they possibly can. People usually use C++ or Julia. All of the fastest answers are in Julia.
> People usually use C++ or Julia. All of the fastest answers are in Julia
That's surprising to me and piques my interest. What sort of pipeline is this that's faster in Julia than C++? Does Julia automatically use something like SIMD or other array magic that C++ doesn't?
I use Rust instead of C++, but I also see my Julia code being faster than my Rust code.
In my view, it's not that Julia itself is faster than Rust - on the contrary, Rust as a language is faster than Julia. However, Julia's prototyping, iteration speed, benchmarking, profiling and observability is better. By the time I would have written the first working Rust version, I would have written it in Julia, profiled it, maybe changed part of the algorithm, and optimised it. Also, Julia makes more heavy use of generics than Rust, which often leads to better code specialization.
There are some ways in which Julia produces better machine code that Rust, but they're usually not decisive, and there are more ways in which Rust produces better machine code than Julia. Also, the performance ceiling for Rust is better because Rust allows you to do more advanced, low level optimisations than Julia.
This is pretty much it – when we had follow up interviews with the C++ devs, they had usually only had time to try one or two high-level approaches, and then do a bit of profiling & iteration. The Julia devs had time to try several approaches and do much more detailed profiling.
The main thing is just that Julia has a standard library that works with you rather than working against you. The built in sort will use radix sort where appropriate and a highly optimized quicksort otherwise. You get built in matrices and higher dimensional arrays with optimized BLAS/LaPack configured for you (and CSC+structured sparse matrices). You get complex and rational numbers, and a calling convention (pass by sharing) which is the fast one by default 90% of the time instead of being slow (copying) 90% of the time. You have a built in package manager that doesn't require special configuration, that also lets you install GPU libraries that make it trivial to run generic code on all sorts of accelerators.
Everything you can do in Julia you can do in C++, but lots of projects that would take a week in C++ can be done in an hour in Julia.
To be clear, the fastest theoretically possible C++ is probably faster than the fastest theoretically possible Julia. But the fastest C++ that Senior Data Engineer candidates would write in ~2 hours was slower than the fastest Julia (though still pretty fast! The benchmark for this problem was 10ms, and the fastest C++ answer was 3 ms, and the top two Julia answers were 2.3ms and .21ms)
The pipeline was pretty heavily focused on mathematical calculations – something like, given a large set of trading signals, calculate a bunch of stats for those signals. All the best Julia and C++ answers used SIMD.
> Part of our interview process is a take-home where we ask candidates to build the fastest version of a pipeline they possibly can. People usually use C++ or Julia. All of the fastest answers are in Julia.
It would be fun if you could share a similar pipeline problem to your take-home (I know you can't share what's in your interview). I started off in scientific Python in 2003 and like noodling around with new programming languages, and it's great to have challenges like this to work through. I enjoyed the 1BRC problem in 2024.
The closest publicly available problem I can think of is the 1 billion rows challenge. It's got a bigger dataset, but with somewhat simpler statistics – though the core engineering challenges are very similar.
The C++ devs at your firm must be absolutely terrible if a newcomer using a scripting language can write faster software, or you are not telling the whole story. All of NumPy, Julia, MATLAB, R, and similar domain-specific, user-friendly libraries and platforms use BLAS and LAPACK for numerical calculations under the hood with some overhead depending on the implementation, so a reasonably optimized native implementation should always be faster. By the looks of it the C++ code wasn't compiled with -O3 if it can be trivially beaten by Julia.
As your comment already hints at, using Python often ends up a hodgepodge of libraries and tools glued together, that work for their limited scope but show their shaky foundations any time your work is outside of those parts. Having worked with researchers and engineers for years on their codebases, there is already too much "throw shit at the wall and see what sticks" temptation in this type of code (because they'd much rather be working on their research than on the code), and the Python way of doing things actively encourages that. Julia's type hierarchies, integrated easy package management, and many elements of its design make writing better code easier and even the smoother path.
> I don't think Julia really solves any problems that aren't already solved by Python.
I don't really need proper furniture, the cardboard boxes and books setup I had previously "solved" the same problems, but I feel less worried about random parts of it suddenly buckling, and it is much more ergonomic in practice too.
My experience with this website is that it would be rather pointless to enumerate, because you will then point to some poorly documented, buggy and supporting fraction of features Julia "alternatives" to Python packages or APIs that are developed and maintained by well-resourced organizations.
The same thing for tooling - unstable, buggy Julia plugin for VSCode is not the same as having products like PyCharm and official Python plugins made by Microsoft for VS and VSCode.
Now, I will admit that Julia also has some niceties that would be hard to find in Python ecosystem (mainly SciML packages), but it is not enough.
> Have you used the language or merely speculating?
> I don't think Julia really solves any problems that aren't already solved by Python.
But isn't the whole point of this article that Matlab is more readable than Python (i.e. solves the readability problem)? The Matlab and Julia code for the provided example are equivalent[1]: which means Julia has more readable math than Python.
[1]: Technically, the article's code will not work in Julia because Julia gives semantic meaning to commas in brackets, while Matlab does not. It is perfectly valid to use spaces as separators in Matlab, meaning that the following Julia code is also valid Matlab which is equivalent to the Matlab code block provided in the article.
X = [ 1 2 3 ];
Y = [ 1 2 3;
4 5 6;
7 8 9 ];
Z = Y * X';
W = [ Z Z ];
Yes, Python code is indeed fast if you write it in C++... what a bizarre argument. The whole selling point of Julia is that I can BOTH have a dynamic language with a REPL, where I can redefine methods etc, AND that it runs so fast there is no need to go to another language.
It's wild what people get used to. Rustaceans adapt to excruciating compile times and borrowchecker nonsense, and apparently Pythonistas think it's a great argument in favor of Python that all performance sensitive Python libraries must be rewritten in another language.
In fairness, we Julians have to adapt to a script having a 10 second JIT latency before even starting...
That's fair - if you work in a domain where you can solve your problems by calling into existing C libraries from Python, then Python's speed is indeed fine.
>I don't think Julia really solves any problems that aren't already solved by Python.
You read the article that compares MATLAB to Python? It's saying MATLAB, although some issues exist, still relevant because it's math-like. GP points out Julia is also math-like without those issues.
In Julia, you explicitly need to still reason about and select GPU drivers + manage residency of tensors; in RunMat we abstract that away, and just do it for you. You just write math, and we do an equivalent of a JIT to just figure out when to run it on GPU for you.
Our goal is to make a runtime that lets people stay at the math layer as much as possible, and run the math as fast as possible.
Sometimes slower? No, always slower. And no one wants to deal with the mess that is creating an interface with C or C++. And I wouldn’t want to code in that either, way too much time, effort, headache.
Why is the `[1,2,3] + [4;5;6]` syntax a footgun? It is a very concise, comprehensible and easy way to create matrices in many cases. Eg if you have a timeseries S, then `S - S'` gives all the distances/differences between all its elements. Or you have 2 string arrays and you want all combinations between the two.
The diag is admittedly unfortunate and it has confused me myself, it should actually be 2 different functions (which are sort of reverse of each other, weirdly making it sort of an involution).
What happens most of the time with unexperienced or distracted users is that they write things like `norm(S - T)` to compute how close two vectors are, but one of them is a row vector and the other is a column vector, so the result is silently completely wrong.
Matlab's functions like to create row vectors (e.g., linspace) in a world where column vectors are more common, so this is a common occurrence.
So `[1,2,3] + [4;5;6]` is a concise syntax for an uncommon operation, but unfortunately it is very similar to a frequent mistake for a much more common operation.
Julia tells the two operations (vector sum and outer sum) apart very elegantly: one is `S - T` and the other is `S .- T`: the dot here is very idiomatic and consistent with the rest of the syntax.
This is about how array operations in matlab work. In matlab, you can write things such as
>> [1 2 3] + 1
ans = [2 3 4]
In this case, the operation `+ 1` is applied in all columns of the array. In this exact manner, when you add a (1 x m) row and a (n x 1) column vector, you add the column to each row element (or you can view it the other way around). So the result is as if you repeat your (n x 1) column m times horizontally, giving you a (n x m) matrix, do the same for the row vertically n times giving you another (n x m) matrix, and then you add these two matrices. So basically adding a row and a column is essentially a shortcut for repeating adding these two (n x m) matrices (and runs faster than actually creating these matrices). This gives a matrix where each column is the old column plus the row element for that row index. For example
>> [1 2 3] + [1; 2; 3]
ans = [2 3 4
3 4 5
4 5 6]
A very practical example is, as I mentioned, getting all differences between the elements of a time series by writing `S - S'`. Another example, `(1:6)+(1:6)'` gives you the sums for all possible combinations when rolling 2 6-sided dice.
This does not work only with addition and subtraction, but with dot-product and other functions as well. You can do this across arbitrary dimensions, as long as your input matrices non-unit dimensions do not overlap.
One of the really nice things Julia does is make broadcasting explicit. The way you would write this in Julia is
Z = [1,2,3]
W = Z .+ Z' # note the . before the + that makes this a broadcasted
This has 2 big advantages. Firstly, it means that users get errors when the shapes of things aren't what they expected. A DimmensionMismatch error is a lot easier to debug than a silently wrong result. Secondly, it means that julia can use `exp(M)` etc to be a matrix exponential, while the element-wise exponential is `exp.(M)`. This allows a lot of code to naturally work generically over both arrays and scalars (e.g. exp of a complex number will work correctly if written as a 2x2 matrix)
Julia competes with the scientific computing aspect of matlab, which is easily the worst part of matlab and the one which the easiest to replace.
Companies do not buy matlab to do scientific computing. They buy matlab, because it is the only software package in the world where you can get basically everything you ever want to do with software from a single vendor.
In addition: Simulink, the documentation (which is superb), and support from a field application engineer is essentially a support contract and phone call away.
I say this as someone who’d be quite happy never seeing Matlab code again: Mathworks puts a lot of effort into support and engineering applications.
I remember the pitch for Julia early on being matlab-like syntax, C-like performance. When I've heard Julia mentioned more recently, the main feature that gets highlighted is multiple-dispatch.
julia is still clunky for these purposes! you can't even plot two things at the same time without it being weird and there's still a ton of textual noise when expressing linear algebra in it. (in fact, i'd argue the type system makes it worse!)
matlab is like what it would look like to put the math in an ascii email just like how python is what it would look like to write pseudocode and in both cases it is a good thing.
Not everything is thrown together code churn. Some tools have earned their keep and don’t need to be in the constant spotlight because they do their job silently and effectively for people such as myself on a daily basis.