Hacker Newsnew | past | comments | ask | show | jobs | submit | lucasoshiro's commentslogin

Cool! But the title made me think that "cigarette smoke effect" made me think that it was about health issues, and I clicked because I was curious about how shaders could be related to that.

Other difference (actually, more like a consequence of what you said) is that Git keeps reflogs for branches but not for tags


> Maybe consider putting your energy into a good documentation inside the repository.

Commit messages are documentation.

If you have a good commit history you don't need write tons of documents explaining each decision. The history will contain everything that you need, including: when and who changed the code, what was the code change and why the code exists. You have a good interface for retrieving that documentation (git log, perhaps with -S, -G, --grep, -L and some pathspecs) without needing to maintain extra infrastructure for that and without being cluttered over time (it will be mostly hidden unless you actively search that). You also don't need to remember to update the documents, you are forced to do that after each commit.

And that's not a hack, Git was made for that.


A surprisingly large amount of devs, do the work to record data into a VCS (probably because they are told to by colleagues or superiors), but never seem to use them. Then they tell you that generating proper commits isn't all that important. Well, that's because they never actually use the VCS. By my book, only generating commits isn't really using a VCS, that is the information generation part, you also need to do queries on the collected data, otherwise yes it would be quite useless.


Agreed. If they don't care about the history, they don't need a vcs. There's no point in keeping a history if the history isn't helpful


I think they somewhat do care about the history, but only as a backup and list of older versions and as bunch of potential merge bases. But they do not care about the history as in the evolution and causality. It really depends on what you see as the history, so it is a manifestation of a somewhat philosophical problem.


> They're all using it, all the time, for everything

Do you know someone? Using Firefox nowadays is itself a "super-online bubble"


Clojure seems to be pretty strong. At least here in Brazil, several companies here use it as their main programming language


> Clojure solves the same problems Rust solves in a much simpler way

I'm curious about that, can you elaborate? I'm a beginner in Clojure and I only know a few concepts about Rust, but it seems to me that they solve (at least, currently) very different problems...

I only saw Rust being used in places where C or C++ would be used in the past (Linux kernel, CLI apps, desktop apps), while I only saw Clojure being used as a modern and functional Java and JS replacement.

Not to mention how different they are as languages (static vs dynamic typing, native vs jvm, borrow checker vs garbage collection)


The main problem that Rust tries to solve, and that functional programming (which Clojure heavily leans into) solves, is avoiding shared mutable state, which leads to data races and (potentially subtly) wrong concurrent programs. Functional programming avoids shared mutable state by avoiding mutable state. Operations are only represented as transformations instead of mutations. Other languages like Erlang / Elixir use message passing techniques like the Actor Model to avoid shared mutability. Instead of avoiding mutability, like in functional programming, in the Actor Model you avoid sharing, by instead sending messages around.

Rust is interesting because it solves the problem of shared mutable state, while allowing sharing, and allowing mutability, just not at the same time. State can be mutated until it is shared. While it is shared, it cannot be mutated. This is the goal of the ownership system in Rust.


> The main problem that Rust tries to solve, and that functional programming (which Clojure heavily leans into) solves, is avoiding shared mutable state

I would argue that avoiding _unrestricted_ shared mutable state is a mean for Rust, not a goal. The main goal would be to provide a way to make safe, fast and non garbage collected programs, which doesn't seem at all what clojure is aiming for.


As proven by ongoing research in things like Linear Haskell, one doesn't need to throw GC productiviy away, to get deterministic resource management.

Best part of Rust is catering to a crowd that not even at point gun will consider touching anything that might resemble having any kind of automatic resource management.

Hence why I consider articles like "How We Saved 70% of CPU and 60% of Memory in Refinery’s Go Code, No Rust Required" [0] interesting to read and make awareness, even if Go isn't one of the languages I happen to be entusiastic about.

[0] - https://www.honeycomb.io/blog/how-we-saved-70-cpu-60-memory-...


Well, erlang and elixir operate on almost exclusively immutable data, in addition to message passing between "processes". They are more strict than most other languages in that regard.


Mutation occurs at the actor level. Their state is mutated by changing how they respond to future messages.


One thing that jumped out at me is you don't need Rust's borrow checker to prevent thread race conditions because data in Clojure is immutable. That's a huge simplification over Rust. What I hear mostly about Rust is complaints about the borrow checker. I wrote a simple Rust utility and found it frustrating. But again, don't take my word for it because I don't know either language.


As someone who has gone deep into both functional programming (with Elixir, Clojure, and Scala) and also Rust, they solve the same problem in different ways with different tradeoffs.

The problem is that shared mutable state is incredibly hard to get correct, especially when concurrency enters the picture.

Elixir and Clojure sidestep the problem by making copying data so cheap that instead of sharing references to mutable data, you make all data immutable and copy it whenever you want to change it in some way. (Which is a classic technique: don’t like the problem? Solve a different problem that sidesteps the original problem in a creative way)

So you have a lot of functions of roughly the shape `f -> f` (return a new thing) instead of `f -> ()` (mutate a thing in place).

This possible at all by the clever use of some novel data immutable structures like HAMTs that are able to approximate the performance of traditional mutable data structures like hashmaps or arrays while presenting an immutable API.

As it turns out, this is a much easier programming model for most of us to get correct in practice (especially in the presence of concurrency) than sharing mutable state in an imperative programming language like C or Java or Python.

The tradeoff is that the immutable functional data structures actually do have a some performance overhead. In most domains it's not large enough to matter, but in some domains it is, and in those domains you really do need mutable state to eek out that last bit of performance.

Which is where Rust comes in.

In Rust's model, data can either mutable or shared, but not both at the same time. The Rust compiler computes the lifetimes of data throughout your program to ensure that this invariant is upheld, so mutable data is not shared, and shared data is not mutated.

The downside of this is that you have to internalize these rules and program to them. They can be tough to learn and tough to program with even after you have learned them, though it does get much easier with experience, I will say.

The upside of Rust's model is that you can have your cake and eat it too: you can keep the high performance ceiling of a true mutable data model while maintaining memory and resource safety.

In short, you can think of Clojure/Elixir as sidestepping the shared mutability problem at the cost of some runtime performance (though again in practice it is smaller than you would think), and Rust as tackling the shared mutability problem head on by transferring the cost of solving the problem to a more complicated compiler and a harder-to-learn programming model.

These are just my opinions having used both Rust and the immutable data functional programming stuff in anger. I'm not trying to present one as being better than the other, the key point is that they're both better than what came before.


My read today is that the advantage of Rust over C/C++ is that the compiler enforces the rules, where in C/C++ you'd have to use a static source code analyzer to find omissions. Since Clojure uses Software Transactional Memory and Persistant Data Structures to only make copies of updated shared data structures, it seems like it could actually be faster than Rust/C/C++ depending on how efficient the copy is. I may have it wrong but it sure is interesting...


While STM was a big selling point when Clojure in practice it's actually very rarely used. The persistent data structures are indeed the heart of Clojure.

While for many applications Clojure's performance is good enough it's not anywhere near what you can achieve with Rust. I once did a small game in Clojure trying to be very clever to eke out every last bit of performance and still didn't hit an acceptable frame rate. Made a very naive reimplementation in Rust that involved copying the entire state every frame and it run buttery smooth.

If there is a task for wish persistent data structures are the most performant solution it should be easy enough to implement and use them in rust too. Probably someone already did that.

Clojure is my default programming language but if I want performance (or static types) I reach for Rust.


That’s my take after using Rust for half a decade. The type system is very powerful and can encode logic in types in a way that’s impossible in most other languages, which is how the borrow checker works (the lifetime of a reference is part of its type).


> can encode logic in types in a way that’s impossible in most other languages

It’d be of great help if you could share an example of this along with an explanation why it’s impossible in a different language say one of Java/C++/Go


> in C/C++ you'd have to use a static source code analyzer to find omissions

Clang and GCC have a pretty solid suite of static checks that they can enforce if you enable them. They catch most of the common footguns.


It's worth noting that there's several implementations of persistent/immutable/functional data structures for Rust already, and a few basic "building blocks" (namely std::borrow::Cow, noted for its bovine superpowers) are even in the Rust standard library. It's possible that we'll see more of them standardized in the future if a case can be made that they're useful and a consensus is reached wrt. some kind of minimally viable APIs.


Did you look into zig and their solution ?


I would argue that F# would be the choice of language in place of Rust if you don't want to deal with Rust's type system. F# is immutable by default with good concurrency and a static type system.


That's a great suggestion I had forgotten about, which is strange since I'm a C# programmer. Part of me wants to really learn a Lisp to see what it is special about it that I keep hearing about. I tried Racket and Steel Bank Common Lisp but they didn't seem appropriate for the commercial programming I'm used to. Clojure is being used commercially.


I also really like Lisps/Schemes. I've always wanted to pick up Clojure but don't like how it thinly sits on top of the JVM compared to F# being deeply integrated. I always had trouble getting Clojure properly installed compared to just downloading .NET and having F# or easily downloading Racket.

You should absolutely try out F#. :) It's a great language.

Also, if you're looking for the magic of Lisp/Scheme, I think you might really enjoy Elixir/Erlang. Elixir has macros, has purely immutable data (there is _no_ way whatsoever to get mutable data unlike F#, Racket, Clojure, etc.), live code updates, and the BEAM VM, its process framework, and OTP are quite magical.

When I first learned Erlang, I felt I had come home. I mainly used Elixir though due to the available packages and jobs.


The late great Joe Armstrong is missed! Good suggestion, I will take a look at Elixer/Erlang. It's the least I can do for the laughs Joe gave me in his videos.


Shameless plug if you like videos: I gave a talk about Erlang, building the language (focus on semantics, not syntax) up from the fact that the = sign doubles as a runtime assertion.

https://youtu.be/E18shi1qIHU

Joe was indeed a great guy. I was lucky enough to spend some private time with him when he was visiting Chicago to give a talk, a true renaissance man with wide-ranging interests.


Good talk! I didn't believe that Go example was real at first. A bit strange. I always think of Alan Kay's message passing objects when listening to descriptions of Erlang and tonight I also thought about Kubernetes pods. The other thought is one you touched on is that some systems are monolithic so you have to handle errors. Thanks, I enjoyed that.


This would be the Elixir talk I'd watch to get excited about it: https://youtu.be/JvBT4XBdoUE


This the “non-low level” code qualification.



Ideally, we should write bug-free code, but we can't. There are some tools to avoid bugs, tests are one of them. Those tools avoid them, but not mitigate. Bisect doesn't replace tests, it only helps find where the bugs are happening. After finding and fixing the bugs, it's a good idea to write a test covering that bug.

To sum up: bisect and tests are not in opposite sides, they complement each other


Git has some really good tools for searching code and debugging. A few years ago I wrote a blog post abot them, including bisect, log -L, log -S and blame. You can see it and the discussion here: https://news.ycombinator.com/item?id=39877637


> bat it's a useless cat

I can't see bat as a "useless cat" or a replacement for cat except for reading source code in the terminal. It's more a like a less with syntax highlight or a read-only vim.


I agree with this. cat is great for "cating" bat is great for throwing shit on the terminal in a fashion that makes it semantically easier to reason with, two different use cases.


There's ccze which colorizes stuff without creating a supposed cat(1) replacement.


Is there a stand-alone syntax highlighting cli tool? It sounds like we need one if one doesn't exist yet. Something that would take an input stream, a language parameter, and maybe an optional color syntax highlighting config or something. It would be something that can be tacked onto any command so the final output has the appropriate syntax highlighting.


Part of the problem is “naming/marketing.” Bat compares ITSELF to cat, not to more/less. IMO, this confuses the issue.


I think that's because it's super common to use cat to quickly view a file. It has the nice property of using your terminal's scrollback rather than putting you into a pager application. For that use-case it is an alternative to cat.

That said, I've never really cared much about missing syntax highlighting for cases where I'm viewing file contents with cat. So the tool doesn't really serve a purpose for me and instead I'll continue to load up vim/neovim if I want to view a file with syntax highlighting.


Maybe it should be called "lest"? As in a less/most replacement written in rust. Although it does divert from the theme of more/less/most.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: