LKML discusses merging Rust access to filesystem APIs
lwn.net
lwn.net
Remind me again why we can't use Pascal? (Except that it's corny, looks funny and I scoffed at it as a youngun.)
I wonder what "C with x" would look like, where x is:
- real composable types
- checked arrays
- maybe some pointer checks?
But no:
- inheritance
- objects
And also very compatible with plain C, not sure if 100% language compatible would be a good idea. Keeping compatibility with C was one contributing reason C++ became so complicated.
But keeping linker and header compatibility would be a godsend.
Maybe realistically what I want is Zig, I realise it's the closest existing fit, even though it has metaprogramming and the syntax is a bit different from C.
I should really learn it to see if I would be happy with it. Currently my go-to languages are C++ if I have the time, C# if I don't and Python if I just want to explore thoughts.
what does this mean, though? writing good, secure C is so hard that literally no one can do it at scale. not Linus, not Theo, not even djb.
why do you find "learning enough to write bad code isn't very hard" to be valuable?
I'm not even really convinced that C is that useful as an approximation of "how computers work" anymore - caches and NUMA and speculative execution and mmap and large numbers of varying ability cpu cores and asynchronous code make C more of an approximation of "how the PDP worked in the 1970s" (with an abstraction layer that is an endless rolling nightmare of critical security issues), which I guess is a bit useful, but not as the thing we base the world on. and a C with array bounds checking and length-prefix strings would still have a shitty type system and no meta programming and not even an iteration protocol (or ability to add a nice one).
> Remind me again why we can't use Pascal?
I would guess it's because Unix-alikes (and for a while Windows, though I guess it had less C and more C++ earlier) ate the world and using the language (almost all of) the OS was written in had huge network effects.
- Don't use libc string functions.
- Use a lot of structs.
- Write a lot of manipulator functions for these structs so you don't get inconsistent data.
- Write in a functional style, don't toss pointers around nilly-willy.
When you follow such self-imposed rules, it's not hard. But you find yourself writing a lot of code doing manually what a more advanced language would just do for you, out-of-the-box. And then you start questioning why you wrote it in C in the first place. (And by "you", I mean "I".)
But what I have discovered is that writing in C is so tedious, it makes me think really hard about the problem to solve so it forces me to do really the bare minimum to solve the problem, which can be a relief if you are prone to over-thinking code and architecture. In C# with an IDE it's so easy to just throw in some abstractions and options and what-not "just in case" which would be a right pain in C.
this is an extremely funny reply, thanks.
Edit:
I think C is easy like the game of Chess. The rules are easy to grok...
I don't want to point fingers so I won't name names, but I took an interest in a certain file system for embedded flash because it was very good, struck a nice balance between features, size and speed, had lots of regression tests etc. In many ways a high quality product.
But wow was it coded very much like that, where to read the code you had to have a full mental model of the layout on "disk" and the layout of the data structures in RAM.
If it had set/get/manipulate_or_update functions operating on structs, then serializing code for the structs to disk, it would have been much easier to read. (And I don't mean heavy serializing, structs with appropriate packing instructions to the compiler would have probably sufficed.)
Edit:
Yet another reason to use structs, don't use naked arrays, put a size_t and the array in a struct.
https://news.ycombinator.com/reply?id=39440071&goto=threads%...
I also think if Pascal existed with a C syntax front-end, 0-index arrays and ditching the Pascal libraries and going for libc by default, I would probably have switched.
On each pascal array you specify both bounds.
So nothing stops you from doing `array[0..4] of Integer` or whatever.
I understand this isn't relevant to the original discussion since the kernel doesn't use libc, but in userland, the flawed design of libc is as much a liability as the language itself IMHO.
For example, maybe you know when to use strcpy(), strncpy(), strlcpy(), memcpy(), but TBH I don't remember the appropriate contexts to use them and I don't write enough C code to warrant actively keep all the nuances in my head.
While inheritance/objects (and even multi-method dynamic dispatch) do exist in the language, they are not widely relied upon in the stdlib or ecosystem in general. Nim has much more lisp-like metaprogramming / syntax macros than C++ (but its richness of syntax for expressiveness compared to sexp's makes such metaprogramming quite a bit more work). Another way to start to describe it might be a far more terse, less factored Ada with more modern lexical aesthetics.
While I know of no specific Linux kernel module-in-Nim project, since Nim can compile to C, it should require no hand holding|permission-slip for Linux integration, although I'm sure it could be made "nicer", as can anything. (People are also writing a few OS kernels in Nim.)
No it really isn't. Newbies struggle with pointers all the time, before they even get to the question of pointer lifetime and what is and what is not safe pointer arithmetic.
> "C with X"
I think the most interesting areas here are Zig and D, although I'm not too familiar with them myself.
Really what we want is an end to "can't spell CVE without C": a language which makes it as difficult as possible to write software which can be compromised remotely.
It would be a worthy project to write a language with the goal of providing the minimum affordances to LLVM IR to make it pleasant to program in, without fully obscuring what you're doing. I'd play around with it.
I'm still sceptical that Rust is this language. It is a somewhat successful languages with lots of people tinkering around, and some mildly successful software (what is the most successful software written in it, btw?). But in a team I'm working in (doing a distributed filesystem), there was an effort do bring Rust into the team and it still isn't easy to gain adoption in the team after a few years. And this is partly credited due to the difficulty of writing in the language.
What I suspect is that a lot of the success is explained by the tooling around the language, making it very easy (especially compared to C) to rely on existing infrastructure. But not necessarily that this infrastructure is particularly easy to write or maintain.
Depends on how you define successful, but I’d probably put money on it being “whataver the few million lines inside of Facebook are doing” or “the few million (probably, I don’t actually know on this one) lines inside of Amazon that they say powers S3, EC2, and CloudFront. Might be the various CloudFlare products, given how likely a given GET request is to touch their infrastructure.
Modula-2 exists since 1978, the only downside versus C in terms of safety, is the use after free still being an issue, everything else was already covered.
Modula-2 was inspired by Mesa, created by Xerox PARC as they desired a secure systems programing to move away from BCPL.
In many regards, Zig is Modula-2 with a syntax more appealing to C minded folks.
On the other hand, small apps that need to "do things with bytes" and want to link to a bunch of dependencies have an appealing answer in Zig because it proposes solving their problem in systematic fashion.
I like Pascal, but the 10x isn't there: it could probably be 2-3x better than C for a lot of things, in the Dephi or FPC variants. It has the bits that people will "write C in C++" for, with much less WTF.
Trust me, I've read this opinion from a certain group before. Whose compositor segfaults on me weekly.
And Rust has neither objects nor inheritance, so.
There is no reason why you can't write simple code in Rust. Well, except that it's tempting to over complicate things. Start using traits and generics everywhere, and you will enter meta-programming in generics hell. Soon after, you will start demanding new compiler features to survive there.
It is also how Swift gets its C and Objective-C interop, and will have its C++ interop as well.
Or how the Java Panama project extracts header file information for native interop.
Say, you have several resources that must be cleaned up in certain order. In C, you would just call the appropriate free functions. When abstracting over that with rust, you have to make an annoying choice:
Do what's in C, don't implement automatic Drop, but mark your functions unsafe. You get leanest zero-cost implementation, it is straightforward to understand, but needs additional maintenance care to prevent bugs.
Wrap resources in unsafe structs that have automatic drop (when goes out of scope). IMO this is a terrible choice, because the maintainer suddenly has to know about which structures have this unsafe cleanup going on. Simple scopes suddenly matter, order of items suddenly matter, it's a mess.
Use reference-counting wrappers to track usage and drop the items when they are no longer in use. Most libraries do this, but it's no longer the leanest possible API.
There might be another choice, to achieve both zero-cost execution and correct cleanup using metaprogramming, be it macros, generics, or both. That's exactly what I fear the most.
The advise provided is good - develop a file system module in rust for ext2 and then propose a new API.
Although I think the point re: the API is not really worth quibbling too much about, I think "Go rewrite ext2 in Rust" is pretty goofy advice, when the purpose is something like "so we will know what the API should look like."
The minute someone implements a filesystem in Rust used by real people is when the rubber will meet the road. Rust filesystems may be different. Everyone is on notice -- APIs aren't stable in the kernel. They especially aren't stable when no one is using them. Something should be there to avoid 8 different implementations, but this endless -- go reimplement an existing facility, as an exercise, teaches us very little, and is mostly a waste of resources (which I'm beginning to believe is the point).
Is there no type tag in the inode structs?
Edit: Looking at its definition I don't see the problem.
int (*link) (struct dentry *,struct inode *,struct dentry *);
Let's then look at the ext4 implementation of the link() operation: static int ext4_link(struct dentry *old_dentry,
struct inode *dir, struct dentry *dentry)
{
...
if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) &&
(!projid_eq(EXT4_I(dir)->i_projid,
EXT4_I(old_dentry->d_inode)->i_projid)))
return -EXDEV;
....
In particular that calls EXT4_I(): static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
{
return container_of(inode, struct ext4_inode_info, vfs_inode);
}
Which is basically just direct unchecked pointer type conversion. So, calling ext4_link() on any non-ext4 created struct inode will blow up badly.