Hacker News new | past | comments | ask | show | jobs | submit | sudarshnachakra's comments login

DuckDB does have ACID guarantees and transactions but I'd not be surprised if they are rarely used (if at all).

Ref: https://duckdb.org/docs/sql/statements/transactions

In the concurrency documentation they explicitly specify that it's not designed for lots of small transactions

Concurrency: https://duckdb.org/docs/connect/concurrency


I had been only following this language with some interest, I guess this was born in gitlab not sure if the creator(s) still work there. This is what I'd have wanted golang to be (albeit with GC when you do not have clear lifetimes).

But how would you differentiate yourself from https://gleam.run which can leverage the OTP, I'd be more interested if we can adapt Gleam to graalvm isolates so we can leverage the JVM ecosystem.


While I indeed worked for GitLab until 2021, Inko's development began before I joined GitLab, and GitLab wasn't involved in it at all.

Inko was hosted on GitLab for a while (using their FOSS sponsorship plan), but I moved it back to GitHub as to make contributing easier and to increase visibility. As much as I prefer GitLab, the sad reality is that by hosting a project there you'll make it a lot harder for people to report bugs, submit patches, or even just find out about your project in the first place. I could go on for a long time how GitLab really wasted its chances with taking over GitHub, but that's for another time :)


I guess linked lists as they are are very useful for implementing queues (particularly those that feed thread pools) where-in the costs of growable array is not needed and the cache locality does not matter (continuing with a thread pool example - It's almost a guarantee that having next element in the cache of the CPU which is not going to execute the next Runnable is a waste).

In Java particularly the both array as well as the linked implementation of blocking queues should perform equally well. FWIW most queue implementations are linked lists.


The best implementations typically have a queue per thread and work stealing. The first threads to finish their assigned work will grab items from other queues, but until then you get perfect cache locality.

Java's queues and global threadpool queues in general are pretty old hat.


> How is that possible? Assuming all things are equal AOT should always be better.

The primary thing here is that the hotter the code path the more optimized your code will be using a JIT (albeit compiled with a compiler which is slower) which is impossible with AOT (since we have a static binary compiled with -O2 or -O3 and that's it) also Java can take away the virtual dispatch if it finds a single implementation of interface or single concrete class of an abstract class which is not possible with c++ (where-in we'll always go thru the vtable which almost always resolves to a cache miss). So c++ gives you the control to choose if you want to pay the cost and if you want to pay the cost you always pay for it, but in java the runtime can be smart about it.

Essentially it boils down to runtime vs compile time optimizations - runtime definitely has a richer set of profiles & patterns to make a decision and hence can be faster by quite a bit.


> Java can take away the virtual dispatch if it finds a single implementation of interface or single concrete class of an abstract class which is not possible with c++ (where-in we'll always go thru the vtable which almost always resolves to a cache miss)

C++ LTO makes devirtualization practical to the point that your browser is benefitting from it right now: https://news.ycombinator.com/item?id=17504370


> Java can take away the virtual dispatch if it finds a single implementation of interface or single concrete class of an abstract class

It can even do that if there are multiple implementations, by adding checks to detect when it is necessary to recompile the code with looser assumptions, or by keeping around multiple versions of the compiled code.

It needs the ability to recompile code as assumptions are violated anyways, as “there’s only one implementation of this interface” can change when new JARs are loaded.


While I tend to agree to the conclusion on premature optimization - I disagree with the assumption that it is premature for most startups. In fact it's a reasonable insurance for startups (that is - if at all they succeed) it'll solve the problem of scale at that point without needing to make huge changes.

BTW Google open-sourced Kubernetes not for charity (like all businesses they also want to make money), they knew they had lost the cloud war with Amazon/Azure gulping up almost 80-90% market share. So they wanted a platform on which they can lure users back to Google Cloud when they start providing kick-ass services (to avoid the much famed vendor lock-in). And since docker was able to solve the dependency management in a reasonable way (not in a very esoteric way like nix) and were dipping their toes into distributed orchestration, they took it as a open fundamental unit to solve orchestration of distributed systems.

But yes Google succeeded in convincing dev/ops to use k8s by frightening them with vendor lock-in. But the most ironic thing that I see about k8s is that all these HPA, Restart on crash all those things are being touted as great new features. These features have existed in Erlang for decades (supervisors and spawning actors). I'm not sure why Google did not try to leverage the Erlang ecosystem - it might have been much faster to market (may be NIH).


> ... it'll solve the problem of scale at that point without needing to make huge changes.

This is incorrect. It's a common mistake to pre-optimise for a future that may never come. I call it "What-If Engineering".

You should always just build a monolith and scale it out as and when you understand what it is that needs scaling. Choosing the right languages and frameworks is where you need to put your effort. Not K8s.

https://martinfowler.com/bliki/MonolithFirst.html


What you say is true, but that is how insurance works - you pay a premium for "What if something unexpected happens", there is a 9 nines chance that it'd not happen but still we keep paying. K8s is similar.


It's because OTP does not integrate with anything not running on Erlang VM, and k8s instead derives from different family tree of general language-independent schedulers/environments.


Language independence is not a trait of k8s it's an artifact of docker packaging java/c++/perl/python/go/rust etc. as an arch dependent image. TBH I find k8s support for languages other than Golang pretty poor (there have been attempts to get java into k8s by redhat with native-image, but it seems to have not made it big).


Language independence is a trait of k8s in the sense that none of its interfaces are in any way specific to a language - the most restrictive in that are the few APIs that are based on gRPC, because state of gRPC libraries is still poor in some places.

Unless you want to embed another language in-process of some k8s components, but the need to do that is disappearing as things are moved out of process.


Hoping this release will bring the below advantages.

1. A statically compiled language with GC-d runtime, which compiles quicker than golang

2. Something that brings algebraic effects to the mainstream and with it an arguably better model for concurrency / parallelism

3. Support value types to take advantage of modern CPU caches

Finally golang finds some real competition (from a very unlikely source though). Hoping ReasonML will become more popular with this release with true parallelism and nice concurrency.


ReasonML is now Rescript, and is still using the 4.06 compiler. I think the idea is to move ahead largely independently of Ocaml, and that a move to 5.0 now is probably seriously ambitious given the runtime overhaul.


So it's Reason, not ReasonML which the umbrella project's name, and Rescript is a imcompatible syntax split from the Bucklescript team (that previously transpiled Reason to JS). Bucklescript's new name is... Rescript.

But not everyone agrees with the split and work is being done on Melange to replace Bucklescript : https://github.com/melange-re/melange

Ultimately JsOfOcaml can directly transpile Ocaml to JS.


> ReasonML is now Rescript

Apparently it's not. The whole thing is a mess :)

https://ersin-akinci.medium.com/confused-about-rescript-resc...


Reason and ReScript are two different projects. You can still use Reason to compile natively and to JavaScript via js_of_ocaml.


Agree that Java is pretty good with records / sealed types / loom, but one nice thing about the Oracle Java team is they do not add half baked features (primarily since they have the last mover advantage) - for (e.g.) Valhalla will have value types, but they'll be immutable so they can be freely copied and used. Loom will have structured concurrency on debut, which IMHO makes vthreads manageable.

But I've my own apprehensions about loom which actually breaks synchronized blocks (by pinning the carrier thread), and are used extensively in legacy libraries and even in the more recent ones (like opentelemetry java sdk).


I like the redis protocol compatibility and the HTTP compatibility, but from the initial skim through I guess you are using abseil-cpp and the home-grown helio (https://github.com/romange/helio) library.

Could you get me a one liner on the helio library is it used as a fiber wrapper around the io_uring facility in the kernel? Can it be used as a standalone library for implementing fibers in application code?

Also it seems that spinlock has become a defacto standard in the DB world today, thanks for not falling into the trap (because 90% of the users of any DB do not need spinlocks).

Another curious question would be - why not implement with seastar (since you're not speaking to disk often enough)?


Yes, helio is the library that allows you to build c++ backends easily similar to Seastar. Unlike Seastar that is designed as futures and continuations library, helio uses fibers which I think simpler to use and reason about. I've wrote a few blog posts a while ago about fibers and Seastar: https://www.romange.com/2018/07/12/seastar-asynchronous-c-fr... one of them. You will see there a typical Seastar flow with continuations. I just do not like this style and I think C++ is not a good fit for it. Having said that, I do think Seastar is 5-star framework and the team behind it are all superstars. I learned about shared-nothing architecture from Seastar.

Re helio: You will find examples folder inside the projects with sample backends: echo_server and pingpong_server. Both are similar but the latter speaks RESP. I also implemented a toy midi-redis project https://github.com/romange/midi-redis which is also based on helio.

In fact dragonfly evolved from it. Another interesting moment about Seastarr - I decided to adopt io_uring as my only polling API and Seastar did not use io_uring at that time.


That blog post is a bit dated. That's the old way. Seastar supports C++20 coroutines.

http://docs.seastar.io/master/tutorial.html#coroutines


Thanks for taking the time to reply - yes in fact seastar does not use io_uring but it's rust equivalent glommio does use it (IIRC it is based on io_uring). Any reasons for using c++ instead of Rust (are u more familiar with it? or just the learning curve hinders the time to market? or is it the Rc/Arc fatigue with rust async? I guess Rust should be a fairly easy language to pick up for good c++ programmers like you)


If I would choose another language it would be Rust. Why I did not choose Rust?

1. I speak fluently C++ and learning Rust would take me years. 2. Foodchain of libraries that I am intimately fimiliar with in C++ and I am not familiar with in Rust. Take Rust Tokyo, for example. This is the de facto standard for how to build I/O backends. However if you benchmark Tokyo's min-redis with memtier_benchmark you will see it has much lower throughput than helio and much higher latency. (At least this is what I observed a year ago). Tokyo is a combination of myriad design decisions that authors of the framework had to do to serve tha mainstream of use-cases. helio is opinionated. DF is opinionated. Shared-nothing architecture is not for everyone. But if you master it - it's invincible.


I guess the Structured Concurrency JEP below addresses the problems you'll get to solve. It'll enable things like AND / OR combinations of virtual threads which IMHO looks like a better way to solve this rather than having a special syntax for select.

https://openjdk.java.net/jeps/8277129

But frankly I'm afraid of how these changes affect garbage collection since more and more vthread stacks are going to be in the heap (I hope they are contemplating some form of deterministic stack destruction along with the above JEP).


Agree with the conclusion of the article that both C++ (mutable/const_cast) & Rust (interior mutability) to hand-wave certain properties they vouch for to enable performance/flexibility.

I guess Rust is better behaved in this regard to ensure that they do not violate invariants in case of types like Cell/RefCell/Mutex, but indeed the design of the language itself caused all these problems for Rust. Because the raison d'etre for Mutex is to share something between threads and calling a lock on it must mutate it, but the language does not allow mutable instances to be shared.

Essentially Mutex is a paradox in Rust, which cannot be implemented but for unsafe.


Consider applying for YC's W25 batch! Applications are open till Nov 12.

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

Search: