"First a punch is just a punch,
Then a punch is not only a punch,
And finally a punch is just a punch" (heard from Bruce Lee)
Basically it means that in the beginning we punch like we can.. then a martial arts student learns the proper and different ways to punch.. so a punch is no longer just a punch... Is a lot of instructions..
Then to sheer practice and repetition the right way to punch becomes second nature.. so the right way to punch is the only way so it's only a punch again.
So coding it's just ifs and loops... Then is OOP and Functional and Logic... But then once you transcend all those paradigms you understand that is all ifs and loops.
Before one studies Zen, mountains are mountains and waters are waters; after a first glimpse into the truth of Zen, mountains are no longer mountains and waters are no longer waters; after enlightenment, mountains are once again mountains and waters once again waters.
I started off writing a lot of 68000 machine code. I was always amazed what you could accomplish with a lot of loops and branches. I never lost that sense that at whatever higher level I was at later on, it was all loops and branches.
The redirection he called an abstraction, and how it makes things easier to make, with less performance and in manh way it’s good, but there’s a point where it isn’t, and solutions like the idea of needing an AI to tell us everything shouldn’t be required.
I like how he talked about using bare metal to run games and not needing an OS, relying on an ISA, or how games were easier to at one point before excessive abstractions.
One very memorable comment he made was when he was asked about what he thought about the M1 chip running software faster, his response was that we could use current hardware and make it run 100x faster if it was well written. Huge part of the many reason I switched to Linux. ;)
ICE has thousands of uses, they aren't just for cars.
An example? Up above the treeline, there are communities relying on diesel for power.
Solar is a no go, with months of darkness. Wind turbines are hard to maintain at -50C, and snow and ice can impede them.
Even electric cars can only cover some of car use-cases, both due to range and refuel time issues.
Expect ICE in 2050 still.
And in most places, electric cars take petrol out of the car, and instead, see things like coal or natural gas burned, to make the electricity to charge them.
> And in most places, electric cars take petrol out of the car, and instead, see things like coal or natural gas burned, to make the electricity to charge them.
This is true, but also a good thing, while you present it as at best a wash and possibly a negative.
Coal powered EVs are better than gasoline ICEs in most situations, and nobody has a 100% coal grid anymore so the benefits are even greater. There's lots of reasons why but the main one, which is relevant to this conversation as well, is the inefficiency of ICE compared with electric motors.
What is more green? Coal or natural gas plants, AC lines that lose some power, building transformers, using AC to DC converters for all our power supplies, refining rare earth minerals to make decaying chemical cells, and using brushless motors (I think?) versus oil drilling with huge machines, refineries, transport and risks of oil spills, and building combustion engines? ICE looks like it can be way more efficient.
Yes. It's actually one of the things that makes EVs greener. A lump of valuable metals in one relatively easy to access and pure form is a lot greener thing to have than a decade of combusted fossil fuels.
I have a feeling that Rule 90 is the most efficient algorithm: the Sierpiński Triangle, self-sacrifice, infinite recursion to a perfect pattern. I'm not mathematically talented enough to prove that though.
Please come to chat about A New Kind of Science on Facebook! A couple of weeks ago I noticed that the page didn't exist, so created it. Hopefully Wolfram doesn't mind. We stand on the shoulders of giants.
I'm no physicist, but doesn't the Standard Model fit on a few pieces of paper? That the universe has rules that are a lot simpler than the behavior that emerges from those rules doesn't seem like novel claim. Wolfram's idea to examine the universe by exploring CA-space is the novel part I think.
Yea, the fuzziness comes from protons shuttling about, tunneling around, electrons moving in cycles with phosphates. It's all just vibrating, bumping and bumbling about. I remember how blown my mind was when I first learned that all reactions catalyzed by enzymes would have happened anyway given enough time and the enzymes just tune the systems to work in concert in a time frame conducive to life.
The organization is only needed for the inevitable bloat you add later to justify the rewrite.
Its something like the sage uncovers the boiler, points at it and announces: Look! It is a beautiful marvel of technology! Why would you want to cover it up? Look! You might learn something!
Coding is not "ifs and loops, then $foo". That's a false premise. If you want to be fundamentalist about it (which I don't advise), a CPU is just a state machine.
assembly instruction + machine state => new machine state
Our idea of "jumping around code" and "control flow", as in for loops or if statements, are themselves abstractions of control state (an instruction pointer) and data state (perhaps a CPU register).
So coding is really "the execution of a notional interpreter (aka semantics), then $foo." That gets to the absolute bottom of what "code" even is: instructions for an interpreting device (be it physical or mathematical).
Oh, but CPU instructions can be built up from a series of μops which are then executed out of order or in an overlapping fashion, making both "instruction" and "state" boundaries in your equation more fuzzy than it looks. So at the absolute-absolute bottom of "code", it is instructions for an abstract model of an interpretative device.
(I'm not sure if your "but" is a retort, or an addendum. Assuming retort...) We can consider one more level of implementation machinery, but I fail to understand how uops aren't another form of instruction, and CPU internal gobbledygook like register files, caches, etc. aren't another form of state. It doesn't seem so fuzzy.
The difference is that you don't get to access the uops machine, subsets/sequences of that instruction set are offered as (macro-)instructions instead. Programming happens on the idea of a CPU.
That's more or less shu-ha-ri https://martinfowler.com/bliki/ShuHaRi.html. Very useful concept, I often refer to it: for example to argue why "just be agile" probably won't work when there's juniors or when the team is new-ish. That's skipping to ri, start with shu (scrum or whatever set process).
That’s what disappoints me in modern Java. There is practically no ifs. It makes it inaccessible to beginners on the project, and the streams are about twice as slow… just because devs think they are more clever if they pile 7 “.map()” to transform a list.
list.stream().filter(Objects::nonNull).map(User::getUsername).filter(Objects::nonNull).filter(name -> name.contains(searchString)).map(name -> “We have found your user: “ + name).orElse(“We haven’t found”);
Basically unreadable.
for (User user : list)
if (user != null && user.getName() != null && user.getName().contains(searchString))
return “Found it!”;
That’s a failure of Java’s language design, not a failure of the functional/declarative paradigm.
Your for loop can do all kinds of damage to the list, and you have to read it all to find out what it does. Saner languages make the functional version more expressive.p:
I’m not saying JS is a sane language; it has an anemic standard library without a robust “first()” or “contains()”. But that code gets you the first user where the name matches, without resorting to indexes or null checks or worrying about how a for loop can mutate lists that it should not.
EDIT: I should have used filter(list fn) here, I was trying to write something plausible in JS instead of a purer functional language and misses that translation.
Hard disagree. For loops do not have guarantees about in-place mutation; that’s why they require a full read. Anything that starts with a map/filter is guaranteed to only apply to the thing that it is assigned to. That’s more than worth its weight in grey hairs.
EDIT: “full read” includes “everywhere else this array is used, which can have far-reaching consequences if it was passed into the containing function by reference.”
Most temporary variables are single assignment, and many newer procedural languages do have variable declaration syntax for single-assignment variables. Such as Javascript's `let`.
Another wide-spread syntax feature is for-loops over collections like `for item in list`, again being extremely easy to read and not requiring any assignments. So, accidental in-place mutation is not an issue in practice. But, in-place mutation can be very useful to express logic in an easy to understand way.
Coincidentally my main language does not have any of these features, and in-place mutation is like 0.1% of all my problems. (And notably, memory management is < 5% of my problems).
These are all just theoretic problems, what really matters is developer experience. You can write terrible bug-ridden convoluted code in any language, ESPECIALLY with many filters and lambdas and callbacks.
The issue with the functional style is that it becomes harder to see the control flow and run-time characteristics. I'm sure functional style is great to express set operations (like DB queries) but IME they tend to optimize for source code brevity and pessimize for runtime performance.
DB queries are a good analogy, especially if we qualify them as atomic operations. I’m hard-pressed to find a situation where procedural mutation-in-place makes more logical sense than an atomic update of the whole list, so why not make atomic updates the default?
It’s different if you’re working in lower-level code. I don’t intend to trivialize performance; the option to “go procedural” should be available. I just think it’s the wrong default. Operating systems and some kinds of Big Data need those perf boosts.
But for your run-of-the-mill CRUD app, map/filter is both clearer and safer than a for loop. Strong language support encourages this both algorithmically and syntactically—unlike what Java did, which is what I originally replied to.
>For loops do not have guarantees about in-place mutation;
Every modern language has a `for elem in range` construct, giving exactly that guarantee, as long as the element isn't a pointer.
Besides, I neither want nor need such a guarantee. There are many scenarios where in-place mutation is exactly what I want to do in a loop, and I don't want to fight the language, aka. my craftsmans tool, to do it, just because it imposes an arbitrary restriction on what I can or cannot do.
Is this a potential source of bugs? Of course it is. That's why I have tests, code reviews and debuggers.
And besides, nothing prevents me from doing the functional approach in languages like Golang, Python or Julia *if I want to*. I simply refuse to use languages that that force a paradigm on my code. This is true not only for "pure functional" languages, but also Java, which wants me to use OOP everywhere.
To me, paradigms are tools.
They need to be there when I need them, and get not get in my way when I don't.
The caveat there is that you cannot call it without a null check on “u.name” first. contains(null, “whatever”) would just return false instead of throwing a runtime exception. Hence my edit: users.filter() has the same problem.
searching for "Jo" returns all three of them in the first example, it stops when the first has been found in the second.
Start including the tedious bits about adding found items to the list and the waste of intermediate variables and your "clear" code is wrapped around a lot of repetitions, that only add noise.
It just happens that you are more familiar with the second style, but pipelines are better in many other ways, clarity of intentions being one of them.
The code he posted isn't actually valid because you can't "orElse" a list. That being said, I would presume it was meant to include a "findFirst". Something like
list.stream().filter(Objects::nonNull)
.map(User::getUsername).filter(Objects::nonNull)
.findFirst(name -> name.contains(searchString))
.map(name -> “We have found your user: “ + name)
.orElse(“We haven’t found”);
The snippets actually do the same thing, as long as you add a .findFirst() to the first example to make it valid Java code.
Intermediate stream operations like map or filter are always lazy. And .findFirst() is a short-circuiting terminal operation, that does not need to consume all stream elements.
with the benefit of being lazy and only inspecting list items up to the first one that matches (and if you don't mutate any data, easily parallelizable)
Modern Java looks horrible to be honest. I create abominations like this in JS pretty often, but it isn't good code. Best if wrapped in a huge try/catch where the error case juwt prints "didn't work for some reason...".
I don't write java, but assuming it has a null coalescing operator you can likely do all that in a single map in a way that is (in my opinion) cleaner and easier to read than both of your examples.
Java has never really liked to do in 10 characters anything that could be done in 30 characters instead, especially if it obfuscated things a bit more at the same time.
I just started using Java's functional side a few weeks ago. Lambdas are really nice and often make the code clearer. I like writing more declaratively.
But the stream interface is just horrible. I had to read a lot before I understood how to just filter a list and collect the results. And even after that, it still somehow didn't scream out what it was doing to me. I guess you get used to it.
When getting start with Zen, I see hill as hill, water as water
When get experienced with Zen, I see hill as more than hill, water as more than water.
When finally got mature with Zen, I once again see hill as hill, and water as water.
And the monkeys reading the code to see what it does. I don’t recall who it was exactly but some early computing heavyweight, maybe Von Neumann, thought that any language which requires a compiler was a waste of resources.
Computers used to be so expensive that it made more sense to hire a “programmer” to convert an “analyst’s” flowchart into machine code using only a keypunch.
As with so many other things, through mastery and practice of the “right ways” you will often discover flaws in them and that is when that which you are practicing begins to become a true art form.
Basically it means that in the beginning we punch like we can.. then a martial arts student learns the proper and different ways to punch.. so a punch is no longer just a punch... Is a lot of instructions.. Then to sheer practice and repetition the right way to punch becomes second nature.. so the right way to punch is the only way so it's only a punch again.
So coding it's just ifs and loops... Then is OOP and Functional and Logic... But then once you transcend all those paradigms you understand that is all ifs and loops.