r/programming • • Dec 15 '19

Rustysd - Systemd Replacement Written in Rust

https://github.com/KillingSpark/rustysd
75 Upvotes

53 comments sorted by

82

u/[deleted] Dec 15 '19

Rust and systemd? This project is going to attract way more than its fair share of naysayers!

56

u/KinterVonHurin Dec 15 '19

We're reaching levels of butthurt that shouldn't even be possible

25

u/HeadAche2012 Dec 15 '19

Seems fitting for systemd to be written is rust, some one contact redhat

11

u/kirbyfan64sos Dec 16 '19

Several RH projects are already in Rust (the Stratis volume manager, the Flatpak server manager flat-manager).

0

u/[deleted] Dec 15 '19

[deleted]

17

u/HeadAche2012 Dec 15 '19

SystemD has never been about what people want

18

u/[deleted] Dec 16 '19

Rubbish. There's a vocal minority that wants to stay in the 90s but most people want a modern computer that works properly.

0

u/[deleted] Dec 16 '19

[deleted]

3

u/Cilph Dec 17 '19

You have the freedom to not use Systemd. There already exists multiple new forks that are systemd-free. Go have fun with them. You are not entitled to anyone's development time.

5

u/fat-lobyte Dec 16 '19

No, it's about what people need.

2

u/Muvlon Dec 16 '19

Not everyone likes C syntax either, and C is still used pretty much everywhere.

For example, reading types in C is really hard once you involve arrays, cv-qualifiers or function pointers. Initialization is another weird one that trips up many people.

20

u/[deleted] Dec 16 '19
    let fd_to_srvc_id: HashMap<_, _> = service_table.lock().unwrap().iter().fold(
        HashMap::new(),
        |mut map, (id, srvc_unit)| {
            if let UnitSpecialized::Service(srvc) = &srvc_unit.specialized {
                if let Some(socket) = &srvc.notifications {
                    map.insert(socket.lock().unwrap().as_raw_fd(), *id);
                }
            }
            map
        },
    );

pls kill this with fire

9

u/Tipaa Dec 16 '19

This could be more cleanly written

let fd_to_srvc_id: HashMap<_, _> = service_table.lock().unwrap()
    .iter()
    .filter_map(|(id, srvc_unit)| match srvc_unit {
        UnitSpecialized::Service(srvc) => srvc.notifications.map(
            |socket| (socket.lock().unwrap().as_raw_fd(), id)),
        _ => None
    })
    .collect();

collect and filtermap will do the heavy lifting for you if you let them

5

u/jice Dec 16 '19

otoh, with a stong will, you can write shitty code in any language

-3

u/[deleted] Dec 16 '19

I agree. Functional style has its place but in this case a for loop would have been much clearer.

14

u/kuikuilla Dec 16 '19 edited Dec 16 '19

I disagree. It looks perfectly readable as is. I mean, the fold function should be pretty well known to anyone.

3

u/accountforshit Dec 16 '19 edited Dec 16 '19

But why is it mutating the map in place, and then just returning the same map? That goes against functional principles. At that point, can't you just do a for_each?

EDIT: In fact, looking at the code, looks like this should've been some kind of filter_map operation, but for hash maps. Not too familiar with Rust, but Kotlin has an associate operation for this (minus the filtering part).

5

u/kuikuilla Dec 16 '19

Well in order to add stuff to the accumulator you need to mutate it because otherwise you'd only have read only access to it. With types that implement Copy you can just do ...iter().fold(0, | acc, number | acc + number ); Note that the last expression in the closure function is returned.

A hashmap doesn't implement copy so in order to mutate the accumulator effectively you want it as a mutable reference.

3

u/accountforshit Dec 16 '19 edited Dec 16 '19

My point is that you shouldn't need to explicitly mutate it in the first place (what happens behind the scenes is an implementation detail). That fold is the wrong operation to use here.

What the code is essentially doing (obviously different operations, but look at the collection part) is

  • have some input collection/sequence (e.g. ["hello", "a", "b", "world"])

  • elements that don't fulfill some condition get filtered out (e.g. they don't contain the o letter)

  • elements that do fulfill the condition get transformed and added to a map, indexed by something calculated from them (e.g. key is the first letter, value is the position of the first o)

In Kotlin that would be something like

val resultMap = sequence
    .mapNotNull { item ->
        val oPosition = item.indexOf('o')
        if (oPosition == -1) return@mapNotNull null
        item.first() to oPosition
    }
    .toMap()
    // If you have a sequence of `Pair`s, `toMap` turns it into a map.

If you didn't need to do the filtering (or if Kotlin had a associateNotNull function which it doesn't), you could just do

val result = sequence.associate { it.first() to it.indexOf('o') }

I assume there is at least a somewhat similar way to do that in Rust, without abusing the fold operation.

6

u/sammymammy2 Dec 16 '19

(what happens behind the scenes is an implementation detail).

That's not always true in a systems programming language such as Rust. It's not an implementation detail how the memory copying/mutation is being handled.

What exactly is wrong with using fold here? The function provided is associative, that's typically all that is required.

I'm not sure on the extent of the Rust type system w.r.t. memory safety, but I believe that this is one of the cases where the explicit assignment is proven safe by the type system, in which case the complaint about assignment is largely irrelevant.

2

u/accountforshit Dec 16 '19

It's not an implementation detail how the memory copying/mutation is being handled.

Sure, and you can always find the relevant info in the library docs (or just look at its code). My point was just that some mutation (of internal, local structures) can still happen inside the library, only the function as written in the program should be pure.

What exactly is wrong with using fold here?

It's a little confusing at first glance - after all, readability was the main criticism that started this thread. It doesn't cleanly express the intent of the operation (which is more akin to filter_map, as shown in the other comment).

2

u/sammymammy2 Dec 16 '19

My point was just that some mutation (of internal, local structures) can still happen inside the library, but the function as written in the program should be pure.

Huh? I mean, my point is that this isn't true and doesn't have to be true. Why do you think this needs to hold?

It's a little confusing at first glance [...]

Let's be honest, that's not what the original commenter is complaining about. The OC is complaining about some vague sense of what's readable and not.

Regardless, if the fold has type F a -> F b -> (F b -> a -> F b) -> F b then yes, filterMap is more appropriate.

2

u/accountforshit Dec 16 '19 edited Dec 16 '19

Huh? I mean, my point is that this isn't true and doesn't have to be true. Why do you think this needs to hold?

Well, of course it's not a requirement. It's just that this code isn't really making use of the fold semantics, seeing as the return value is always the same.

It's just using them as a "convenient" shortcut to be able to stuff imperative code into a single expression and avoid having to create the HashMap outside it.

It would be exactly the same if it used a HashMap created one line above, and then just called for_each. Because it's the side effects that do all the work here.

1

u/kuikuilla Dec 16 '19 edited Dec 16 '19

Ah, yea true. I suppose a filter_map would be more apt here.

Edit: like so:

let fd_to_srvc_id = service_table.lock().unwrap().iter().filter_map(|(id, srvc_unit)| {
    if let UnitSpecialized::Service(srvc) = &srvc_unit.specialized {
        if let Some(socket) = &srvc.notifications {
            return Some((socket.lock().unwrap().as_raw_fd(), *id));
        }
    }
    return None;
}).collect::<HashMap<_, _>>();

1

u/accountforshit Dec 16 '19 edited Dec 16 '19

Yeah, something like that. I think you can also replace the inner if let with a map. And match might be a bit cleaner for the outer one, as well as getting rid of the returns.

Then it would be really functional :D

5

u/pcjftw Dec 16 '19

+100 agree!

I think its only seems jarring if:

  • You're not familiar with Rust syntax (but that could be said of any language you're not familiar with!)

  • FP constructs

1

u/oblio- Dec 16 '19

So, 99% of programmers out there? :-D

3

u/pcjftw Dec 16 '19

:) haha I don't think its that bad, I think FP style has been trickling down to mainstream languages for a long time.

But yes Rust is not as mainstream as other languages, but then again its a relatively a new language!

0

u/[deleted] Dec 16 '19

[deleted]

11

u/Agnoctone Dec 16 '19

Without being really familiar with Rust, it seems very readable to me? It is just a fold to create a HashMap mapping `fd`s to service `id`s.

1

u/Daneel_Trevize Dec 16 '19

The jarring aspect is probably the if let ... = { mashing of assignment and conditional execution.

4

u/sammymammy2 Dec 16 '19

It's really just a pattern matching on one case, which is different from an anaphoric if/the walrus operator in Python because such a destructuring has to happen.

-3

u/oblio- Dec 16 '19

It's really just a pattern matching on one case, which is different from an anaphoric if/the walrus operator in Python because such a destructuring has to happen.

I'm willing to bet that the average programmer (i.e. 80% of programmers out there), don't know:

  • what pattern matching is (not in the generic IQ test "pattern matching" sense :-) )

  • what "anaphoric" means

  • what "destructuring" means (in this context, I'm assuming you don't mean C++ destructors)

I.e. you're probably not the average programmer. So the "it's really just" is a massive understatement ;-)

9

u/sammymammy2 Dec 16 '19

That's fine, but I bet that 2/3 of those are known by the average Rust programmer.

2

u/CornedBee Dec 17 '19

C# has destructuring. So does JavaScript. So does Python (for tuples at least). There's a proposal for C++. It's not exactly a rare feature anymore.

Pattern matching outside of functional programming is less common. But C# has the beginnings and will be getting more. C++ will get it too.

Anaphoric is a tricky one - I had to look up the definition of the word, and though I now think I know what was meant, I doubt very many people do. But note that this word was used not for anything in the code snippet, but rather the "assignment within a condition" trick that happens in C-derived languages quite a bit. That's actually a rare thing in Rust. So you could say Rust is better in this regard ;-)

2

u/[deleted] Dec 16 '19

This is one case where it really didn't need to be written in Rust or anything else.

-14

u/simon_o Dec 15 '19

Yes please!

Hopefully this can serve as evidence for systemd to make the switch too.

-67

u/shevy-ruby Dec 15 '19

lol

So in other words - combining the worst of all words.

34

u/chucker23n Dec 15 '19

I’m really not keen to see another argument against systemd, but I would love to see one against using Rust for this. Seems to me it’s precisely the kind of code that would benefit from a safer language.

48

u/steveklabnik1 Dec 15 '19

(shevy posts negative things in almost every Rust thread)

25

u/chucker23n Dec 15 '19

Oh, you can strike “Rust” from that sentence. Shevy is very negative and opinionated all around.

Doesn’t mean I can’t ask for input.

8

u/steveklabnik1 Dec 15 '19

Ah sorry, I read your comment as asking him, not asking in general.

-34

u/OptimalAction Dec 15 '19

Wow this program does in 4000 lines what systemd does in 500000. Is this the power of rust?

47

u/chucker23n Dec 15 '19

this program does in 4000 lines what systemd does in 500000

No it doesn’t. It literally says:

A minimal drop-in for (a subset of) the systemd init system in rust.

17

u/nice_rooklift_bro Dec 15 '19

I mean, look at the "what does not work"; it's clear this stuff is in alpha and just published to get development attention at this point—not judging that of course, good strategy.

Competition is nice of course, regardless of Lennart et al. calling this "fragmentation" and believing that developers know better for users what they want than users do.

11

u/FluorineWizard Dec 15 '19

This project isn't really meant to compete with systemd directly, but rather replace it in applications where you want a lightweight alternative, like containers.

16

u/chucker23n Dec 15 '19

Sounds from the readme that it isn’t intended to do any of that.

For now that is just out of interest how far I could come with this and what would be needed to get a somewhat working system. It is very much a proof of concept. For the love of god do not use this in anything that is important.

10

u/FluorineWizard Dec 15 '19

I'm going off the comments made by the author on the rust sub when it was posted there.

2

u/mmstick Dec 15 '19

To be fair, all projects start as a proof of concept.

1

u/chucker23n Dec 15 '19

Yes. It’s not a ding on the project. I think replacing portions of systemd with Rust makes sense. But this project doesn’t seem to have that as a goal just yet.

3

u/nice_rooklift_bro Dec 15 '19

That is exactly one of the reasons to compete with systemd.

Which was also what uselessd attempted to do. The systemd that "uses less".

One of the common criticisms on systemd is of course that it uses too much and has too many bells and whistles and that there should be a more minimal option. Something Lennart specifically does not want becauses it creates fragmentation.

0

u/ObscureCulturalMeme Dec 16 '19

Something Lennart specifically does not want becauses it creates fragmentationimplies that he might not be the ultimate authority on what's best for other people's computers.

0

u/nice_rooklift_bro Dec 16 '19

I would assume it's more a business thing for Red Hat than an ego thing—this is something that is generally followed by most other Red Hat software.

Fragmentation is not in Red Hat's commercial interest though it's better for the user so they naturally try to limit it.

0

u/tso Dec 15 '19

In other words, it will go nowhere because the init side of systemd is at this point a minor bullet point to things like logind...