12 ms·
This right here is why I think Rust really stands out from other languages. You can call it from other languages just as you can call native code written in C.
by exDM69 11y ago
This right here is why I think Rust really stands out from other languages. You can call it from other languages just as you can call native code written in C. It's not married to a complex runtime system.
Most other languages are "dead ends", because code written in them is not easily reusable from other languages.
- dangerlibrary 11y agoIt's easy to call any code from any language - all you need is the power of HTTP and micro services! ;)
- dikaiosune 11y agoMicroservices don't help polyglots make regexes faster. If you're sticking a 100ns operation behind an endpoint with JSON serialization/deserialization, network round-trip, etc., then I'm not sure what to say to that.
- sixbrx 11y agoNote wink at end of dangerlibrary's post!
- dikaiosune 11y agoA wink does not necessarily mean sarcasm? I agree that in this case it probably does, but I don't see how that use of sarcasm adds anything substantive to the conversation (aside from a not-relevant-to-this-post dig on microservices, perhaps).
- cderwin 11y agoActually this microservices approach has existed for decades in erlang/otp and can maintain quite excellent speed. You're not going to beat raw c speed-wise, but typically you will beat comparable dynamic languages -- and you don't have to worry about decoding/encoding json or any of that bs. I'd personally be absolutely thrilled if something like genserver and some other otp protocols were ported to other dynamic languages -- but alas real processes aren't nearly efficient enough.
- vvanders 11y agoYou can also delegate to C with Erlang via NIFs
- steveklabnik 11y agoThen there's https://github.com/hansihe/Rustler https://github.com/hansihe/Rustler
- vvanders 11y agoYes, that's been on my (long) list of things to check out.
- btrask 11y agoI wish you were joking.
- xaduha 11y agoGranted.
- jkrems 11y agoReminds me of this: https://blogs.oracle.com/angelo/entry/url_encoding_and_other_from https://blogs.oracle.com/angelo/entry/url_encoding_and_other...
- xiaq 11y agoOn a serious note, implementing libraries as standalone applications that can be accessed via IPC is actually a viable approach. Plan 9 does this with almost all of its services. Not exactly a fair comparison though, since the IPC mechanism in Plan 9 is just the file system and much easier to learn.
- pjmlp 11y ago> This right here is why I think Rust really stands out from other languages. You can call it from other languages just as you can call native code written in C Which is only true, when we forget about the history of computing before C was widespread outside AT&T and C ABI became a synonym for OS ABI. Rust is great, and a very good step forward in terms of safe code, but lets not forget the ones that came before.
- catnaroek 11y agoDid any of those provide safety by means of compile-time checks (as opposed to sophisticated runtime systems, which are by necessity more expensive), though? AFAICT, Lisp didn't, Smalltalk didn't and Oberon didn't.
- pjmlp 11y agoNot all the use cases that Rust covers, but many of the typical errors that are possible in C, yes. For example, the NEWP in MCP only allowed unsafe code in modes where the system administrator would configure them as such, back in 1961. https://en.wikipedia.org/wiki/Burroughs_MCP https://en.wikipedia.org/wiki/Burroughs_MCP https://en.wikipedia.org/wiki/NEWP https://en.wikipedia.org/wiki/NEWP
- catnaroek 11y agoIf you need unsafe code to implement the garbage collector and other core system facilities, then “selectively” disabling safety doesn't really mean much, does it? Also, determining whether code is safe to run requires proof, not trust. Since when are system administrators particularly skilled at coming up with proofs?
- pjmlp 11y agoWho said anything about NEWP using a GC?! Also the type of enabling/disabling unsafe code in those lanugages was not much different than running "rustc -D unsafe-code" Also computer admins in the 60's were programmers.
- 0xFFC 11y agoWhat do you think of IPC ? in terms of performance and usability. (BTW I am genuinely asking)
- jstimpfle 11y agoAssuming that you imply serialization and message passing here: probably too slow for many useful library functions.
- derefr 11y agoHow about message-passing without serialization? Imagine that what we got in the 1970s instead of Unix was something like an Erlang VM, in the sense of each OS "process" having an inbox ring-buffer to which other processes could write; and every process having a set of basic agreed-upon tagged types, such that processes could stick raw-memory structs into other processes' inboxes, as long as they consisted only of those basic tagged types.
- jstimpfle 11y ago> basic agreed-upon tagged types Anything going beyond ASCII/UTF-8 or C types will be very hard to agree upon. And I think there is no way around serialization ( == chasing pointers and converting to a contiguous chunk of memory). Except if you restrict to a single language ecosystem like Erlang or Haskell, which enable data sharing between (often userspace-) threads in a shared address space. But these need a much more complex runtime.
- derefr 11y agoAlmost every "language ecosystem" has a runtime which itself—at least on ⋆nix—relies on libc. This is why every modern language exposes e.g. a FILE type with the same semantics; they're all just wrapping the libc FILE struct + API. What I'm imagining is a world where "libc", from way-back-when in the 1970s, exposed declarations for some more interesting ADT types + APIs than just register-sized scalars and ASCIZ strings. Not types that require heap allocation or anything, mind you; just some fancier on-stack value types. Imagine the C runtime being just "batteries-included" enough that if you were writing, say, a JSON parser in C, there would be obvious "native C types" to decode each of JSON's container types into. And now imagine a world where every modern "language ecosystem" had been built up on top of this libc, instead of the one we have. A libc one can rely on to represent almost all the basic types one needs in a well-known (or at least, consistent per machine) manner in memory. Imagine how easy message-passing IPC would become in such a world.
- deleted 11y ago[deleted]
- giovannibajo1 11y agoThis only works for simple algorithms that don't touch the system. As soon as you try to bind something that handles a file on disk, a socket, a thread, it's wishful thinking anyway, as any language have different ways and paradigms to approach threading, asynchronous I/O, signals and other runtime-level issues, and getting code from a different language / library / paradigm is probably not going to fly, or even introduce subtle bugs. For instance, if I bind a Rust library that opens a file on disk and use it from Go, I lose all the benefits of the Go runtime like the fact that the FD is not inherited by sub processes (as Go always uses O_CLOEXEC, while glibc doesn't), or the fact that blocking calls never return EINTR to application code in case of signals (the Go runtime handles this for the application). So you might think that the library works, while its subtly violating your language's runtime conventions in a way that might cause hard to debug bugs in production. One of the benefit of writing code in single "modern" language/runtime is that you don't have to worry about these hairy issues.
- pcwalton 11y agoNote that the Rust standard library also sets O_CLOEXEC. https://github.com/rust-lang/rust/pull/24034 https://github.com/rust-lang/rust/pull/24034
- burntsushi 11y agoIt feels like you're throwing the baby out with the bath water, and I don't think a good regex library could be classified as "simple." I specifically wrote Go bindings to Rust's regex lib in tandem with the C API to make sure I wasn't baking any assumptions into the C API that would make it difficult for another language to bind to them. This process was lucrative. My first draft of the C API defined an iterator that held on to a pointer to the text being searched for the lifetime of the iterator. It turns out that this is inconvenient to use from a language like Go (or perhaps, any language with a moving GC) because C holding on to pointers to memory allocated in the host language can be bad juju. Because I did this process in tandem, I was able to correct the issue at the C API level. As a result, if you need fast regexes in Go, you now have an option, and that option is built on a reasonably mature regex library with thousands of tests and a benchmark harness that sports PCRE1, PCRE2, Tcl, RE2 and Oniguruma, of which, Rust's regex engine compares quite favorably.
- falcolas 11y ago> ... because code written in them is not easily reusable from other languages. Which is also technically true for C as well. The ABI [EDIT: Not API] is an implementation detail which can vary from compiler to compiler. So long as you're just using LLVM-based compilers for both Rust and your other languages, you should be OK, but don't be surprised if you run into problems.
- masklinn 11y ago> Which is also technically true for C as well. The API is an implementation detail which can vary from compiler to compiler. The C ABI (API is less relevant there) is really the platform/OS's calling convention, which — aside from Microsoft (and embedded systems I guess, because embedded) — is generally the architecture's calling conventions. Which are usually well documented. > So long as you're just using LLVM-based compilers for both Rust and your other languages, you should be OK, but don't be surprised if you run into problems. As long as all the languages involved use the same ABI you're in the clear, that's got nothing to do with LLVM. That's what cgo does on the Go side[0]. And as pcwalton notes in an other comment, in theory you could even have the Rust FFI follow the Go/Plan9 ABI. [0] at a significant cost for the default toolchain since `gc` doesn't use the platform ABI. I believe the gccgo-based alternative toolchain has no cgo overhead.
- burntsushi 11y ago> So long as you're just using LLVM-based compilers for both Rust and your other languages, you should be OK, but don't be surprised if you run into problems. No. You can use the Go bindings to Rust's regex library where the regex library is compiled with `rustc` (llvm based) and your host program, written in Go, is compiled with the standard Go compiler, which is not llvm based. This works because the Go toolchain knows how to link with objects exposing a C ABI and the Rust toolchain knows how to provide said objects. There is no particular dependency on llvm here.
- Manishearth 11y ago- Calling into the C ABI is a stable and well documented operation that most languages support in some form - Rust allows you to export functions with the C ABI - LLVM wasn't involved here at all
- tyingq 11y ago>>Most other languages are "dead ends", because code written in them is not easily reusable from other languages. FFI isn't the only way to be reusable from another language though. Many interpreted languages are easy to embed into C, C++, and often other languages.
- duaneb 11y agoYes, but the conversion between domain types is the killer there. Have you ever tried embedding ruby into python (or vice versa?) The string/unicode/bytes conversions alone demand a full project's worth of work. Basically, having base types convert toll-free is HUGE.
- tagrun 11y agoRuntime doesn't necessarily mean "can't call from other languages". Languages with runtimes can still conform to C ABI on that arch. You can call Go from C, or even from Java on Android out-of-the-box (and Objective C on iOS), for example.
- Jweb_Guru 11y agoYou can call Go from C, but it's extremely slow and requires special handling of GC'd references (among other things). It's not really a suitable replacement for C bindings in many circumstances.
- exDM69 11y agoTrue on all accounts but you forgot the "easily" part. Installing JVM and then writing JNI wrappers isn't really easy reuse. You just don't see Java or Go code (let alone both) used in programs predominantly written in another language.
- robohamburger 11y agoWhat will be interesting is when rust gets its own ABI. There is an rfc for it even: https://github.com/rust-lang/rfcs/issues/600 https://github.com/rust-lang/rfcs/issues/600 Hopefully if such a thing exists you could link directly to a rust library from other high level languages and possibly even have lower overhead. For now being able to do the equivalent of extern "C" is not that new but still really useful I suppose.
- kibwen 11y agoI wouldn't quite say that's an RFC, it's just an issue in the RFCs repo. Typically people use the issue tracker in order to represent RFCs that they would like to see written, sort of a wishlist.
- robohamburger 11y agoAh I misunderstood! Thinking about it a bit more and given how heavily rust uses generics it seems like having an ABI that is at all usable by another higher level language might be challenging. I guess there is always compiler plugins though :)
- PeCaN 11y agoAda does this with the rather convenient pragma Export(Convention => C, Entity => My_Ada_Function, External_Name => "mypackage_ada_function"); You can kinda coerce D and C++¹ to do the same thing, but this is definitely something Rust and Ada got really right. -- ¹Okay I lied, C++ does this pretty easily with extern "C". However, C++ APIs frequently do not convert well to C at all and you often have to write wrappers for them. C++ classes in particular just can't cross ABI boundaries without a lot of pain, while Ada records and Rust structs are usually just a pragma away from being accessible from C (their “methods” don't use a special calling convention; method calls are just syntactic sugar for passing a struct as the first argument).
- nitrogen 11y agoThe x86 C++ ABI convention of passing this in ECX probably caused a lot of C interop headaches over the years, but really, C should have been passing the first argument in a register anyway.