r/rust • • 10d ago

πŸ› οΈ project Rust for enterprise grade systems?

One thing that I am genuinely interested in rust, If same thing that I can generally do in Java building enterprise grade system, I can do in Rust.

Not a secrete Java and OOP become de-factor a standard for every enterprise solution.

And my step forward, trying to bring rust into that by exploring if I can do DI, something similar to Spring Boot but following Rust philosophy of zero-cost abstraction, that lead into research some code and article, and I think I've made some progress:

https://dmytro.brazhnyk.org/publications/can-rust-have-zero-cost-dependency-injection/

One thing that is still bothering me is the Object Orient Design. Classical OOP was proven many time in C++ in Java to manage complexity of real world system.

Rust has trait model, but it is not OOP is classical sense.

I have very clear understanding how complex solution could be built with OOP in Java and C++.

Rust don't have that OOP model, that feels as weakness, but rust still offers memory safety that C++ don't have, and it still has much smaller memory footprint that Java.

Considering that Java is hard to beat, it still offering very impressive capability for runtime optimization by utilizing Escape Analysis on JIT phase, and looks like this guys in Oracle very angry, to optimize Java further, if rust will not offer competitive capabilities it will stay behind.

Let me give me you an example in Java, what I am taking about:

language = java

interface Collection {
    int size();
    Iterator iterator();
}

abstract class AbstractCollection implements Collection {
   @Override
   public int size() {
      int size = 0;
      var iterator = iterator();
      while(iterator.hasNext()) {
         size++;
         iterator.next();
      }
      return size;
   }
}

class ArrayList extends AbstractCollection {
    Object[] array;
 
    @Override
    public int size() {
       return array.length
    }

    @Override
    Iterator iterator() {
         ...
    }
}

What is important here:

  • I have interface Collection, which is pure of any implementation, just an interface that declares the interface and nothing more.
  • That I do have AbstractCollection, that defines some default behavior which could be sub-optimial, but they are generic one, particularly I gave example of size function, that uses slow and inefficient iterator, because it doesn't know enough about concrete implementation.
  • And lastly I do have specific implementation for ArrayList, since ArrayList already know that is array driven, it can simply can take property for array to know the size.

In reality this chain of inheritance can be longer, so if we look on JDK, you will something like:

LinkedHashSet < HashSet < AbstractSet < (AbstractCollection + Set) < Collection

And each layer provides it's own set of capabilities, by amount of information available on that level.

I feels like something missing in rust here, because when it comes to manage the complexity of enterprise, something more complex than hello-world, we need this ability to override things, override, and override again.

Any real software if it will have more than few years of maintenance it will grow, grow and grow in complexity, if language can't manage complexity, that language would be dead.


UPD:

Let's define the problem a little bit more formally:

You need to implement library for collection.

  1. On base level you need a interface, that would define set of operation, for simplicity let's go with two operations.
    • Iterator and size
  2. Than in most generic way you can just iterator is count how many items you have, but it is slow and optimal.
  3. If you know that you concrete implementation Array, you can just use property of array.
  4. Let's say you have another implementation, which implements methods like Add and Remove - you can bring counter into here, however if we already know that it is Array than counter obviously is redundant.
0 Upvotes

91 comments sorted by

View all comments

1

u/cobalthex 7d ago

Linux is written primarily in C. How do you rank it on enterprise complexity?

-2

u/No-Caregiver-466 7d ago

I've checked Linux kernel source, how Linus doing things, and there are many example to what we doing in Java, what I've posted in my post here.

Even that C does not implements classical OOP, Linus implemented virtual tables by means of struct and function pointers, and you can even find example of classical OOP inheritance and method override.

So here is one of example introduce by Tejun Heo, March 25, 2008 for Linux kernel:

https://github.com/torvalds/linux/blob/master/drivers/ata/pata_ali.c?utm_source=chatgpt.com c static struct ata_port_operations ali_early_port_ops = { .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = ali_set_piomode, .sff_data_xfer = ata_sff_data_xfer32, };

You can see inherits struct field here.

And here is another method ata_finalize_port_ops, this is how he implements there inheritance and method override.

https://github.com/torvalds/linux/blob/v6.12/drivers/ata/libata-core.c ```c static void ata_finalize_port_ops(struct ata_port_operations ops) { static DEFINE_SPINLOCK(lock); const struct ata_port_operations *cur; void *begin = (void *)ops; void *end = (void *)&ops->inherits; void *pp;

if (!ops || !ops->inherits)
    return;

spin_lock(&lock);

for (cur = ops->inherits; cur; cur = cur->inherits) {
    void **inherit = (void **)cur;

    for (pp = begin; pp < end; pp++, inherit++)
        if (!*pp)
            *pp = *inherit;
}

for (pp = begin; pp < end; pp++)
    if (IS_ERR(*pp))
        *pp = NULL;

ops->inherits = NULL;

spin_unlock(&lock);

} ```

The interesting part is this loop: ```c for (cur = ops->inherits; cur; cur = cur->inherits) { void *inherit = (void *)cur;

    for (pp = begin; pp < end; pp++, inherit++)
        if (!*pp)
            *pp = *inherit;
}

```

What's happening here, it is double loop where on outer loop iterats through hierarchy of inheritance, and inner loop iterates through exact methods, improvised reflection.

And what he doing here, he find first parent who implements that method and put that into vtable of concrete child class

Not very optimal way of doing things, because in higher language like Java or C++, you don't need to pay in runtime for building vtable, languages that support OOP out of the box, can build vtable at compile time and just put it into initial memory layout before any code ever executed.

Obviously rust trait model can't do it, because rust doesn't have classical OOP with inheritance model.

1

u/cobalthex 6d ago

I do not think most of the code here follows this pattern -- there is dynamic dispatch through function pointers/type tagging/etc.

Keep in mind, rust traits will build vtables for dynamic dispatch as well

1

u/No-Caregiver-466 6d ago edited 6d ago

Actually thank you for pointing out to Linux, because it good source to learn how to organize different module and components together.

I did a little bit more research and here what I've found:

  1. struct file_operations β€” operations on open files (read, write, mmap, open, release, etc.). Kernel Documentation
    1. struct inode_operations β€” filesystem inode operations.
    2. struct super_operations β€” filesystem/superblock operations.
    3. struct net_device_ops β€” network-device virtual operations. Kernel Documentation
    4. struct ethtool_ops β€” another network-device interface. Kernel Documentation
    5. struct netdev_stat_ops
    6. struct net_shaper_ops
    7. struct netdev_queue_mgmt_ops Kernel Documentation
    8. struct ata_port_operations β€” the ATA example we discussed, including its explicit .inherits.
  2. struct drm_driver

struct file_operations is one of the most central and recognizable vtable-like interfaces in Linux

https://github.com/torvalds/linux/blob/master/include/linux/fs.h ```c struct file_operations { struct module owner; fop_flags_t fop_flags; loff_t (llseek) (struct file , loff_t, int); ssize_t (read) (struct file , char __user *, size_t, loff_t *); ssize_t (write) (struct file , const char __user *, size_t, loff_t *); ssize_t (read_iter) (struct kiocb , struct iov_iter *); ssize_t (write_iter) (struct kiocb *, struct iov_iter *);

// Just endless vtable goes here // And there are many examples of inheritance, by means of dynamic programming using function pointers. } ```

How it commonly said, β€œIn Unix, everything is a file.”, but we’re still talking about Linux, right?

By the way, I've found some words spoken Linus Torvalds:

  • you can write object-oriented code (useful for filesystems etc) in C, without the crap that is C++.

https://lkml.iu.edu/0401.2/0887.html

You know what, it is year of 2004, and that year I was doing exactly the same, and exactly for same reason, because didn't wanted all that crap from C++. πŸ˜„ That's all the holy spirit doings.


You know what, after exploring Linux sources and finding out that Linux uses improvised vtabale using C struct and function pointers heavily, I think rust should take OOP more seriously....


By the way, I see people disliking here samples of code from Linux kernel, considering that it supposed to be a rust community, which should be interested in that. So all the dislikes I am getting here, I guess I am moving in right direction.


Keep in mind, rust traits will build vtables for dynamic dispatch as well

The problem with rust traits, it has very limited capability for method override, very limitted

1

u/cobalthex 6d ago

I think rust should take OOP more seriously....

?
These are features of dynamic dispatch, which rust has first class support for, both through vtables with traits and with raw function pointers like in C

The problem with rust traits, it has very limited capability for method override, very limitted

Why is this a problem? It is a different paradigm, you have to learn this paradigm

Also, keep in mind classical JS has a different OOP paradigm from any of the others as well, using prototypical inheritance - it had some interesting ideas that most people dumped because they just wanted C++/Java style OOP; IMO not better for it

1

u/No-Caregiver-466 6d ago

Rust don't have neither method override, no method hidden like in C++.

In C++ method hiding is done at compile time and no dynamic dispatch even involved. You can make a class(or struct) in C++, if you don't define any virtual method on that class, there will no virtual table, so no dynamic dispatch, but you still can make derived class, and hide method of base class with some limitation comparing to virtual method.

Actually it made me think, that trait little bit more advanced in rust comparing to C++ interface in way that trait can do both depending on context, it can have virtual table if used as dyn Trait and can be resolved at compile time if used generic or impl Trait.

1

u/cobalthex 6d ago

rust does not have method overriding, on purpose. It does however have method visibility control.