As in: keeping it clean and well structured is impossible and the impressive flexibility of the language is huge downside on larger projects.
I feel qualified to say such things as I've worked on a billion-line perl codebase before.
> As in: keeping it clean and well structured is impossible and the impressive flexibility of the language is huge downside on larger projects.
Perl gets quite unfairly picked on here, to the point where it's basically a meme. It's not like, just to pick a somewhat popular language, Ruby doesn't provide plenty of ways to write completely unreadable code that can only be understand by running it through irb, if even then.
I agree that there is plenty of bad Perl code out there, but there's plenty of bad code in any language that achieves general popularity for a time. Disciplined use can produce perfectly clear and readable code and the module system is perfectly adequate for separation of concerns.
The language does give you an absurd amount of rope to hang yourself with though. If I were managing a large Perl project today I'd have an extremely restrictive style guide and would enforce as much of it as possible via pre-commit hooks.
> I feel qualified to say such things as I've worked on a billion-line perl codebase before.
For a language that permits such densely expressive code, that's appalling. I'm so sorry.
This was surprisingly doable? Marshaling/unmarshaling Perl objects into Python ones isn’t difficult these days, and you can run Perl code via FFI so the transition can be piecemeal.
I have no opinions on Perl as a language (some constructs / patterns felt a bit hard to think about, but I’m far from an expert), but ultimately it’s a high level language and has been left behind tooling wise to another high level language, so it’s time to move. For us, one motivator was that having a large legacy Perl codebase (even one running well for years) hurt recruiting.
I feel like - opinion, not based in fact, I've never worked on any codebase >1M LOC - the only way you can keep a codebase like that maintainable is by very strict code style and architecture rules - e.g. no functional programming, no feature X, no feature Y, strict code style rules, strict architecture rules, etc.
Personal experience. We have some java code from 15-17 yrs back. About the time “design patterns” and all the other “pattern” stuff was big in everyones mind. It’s a mess of abstraction for simple tasks. Couple all that with the fact that class instantiating is possible via reflection and at this point people maintaining it have kinda given up. It works - don’t touch it.
This isn’t an indictment of Java. Just resume driven design.
Programmers are highly trained like to see the world as if everything can be cast the same way. While that IS a good way to see a large variety of software problems, when you isolate down to a companies' use cases, it quickly goes away in the pragmatic sense. It then becomes something the company is paying for because they chose Java and Java developers like that sort of thing.
Long ago I worked primarily in perl and ... yeesh, I recognize maybe 30% of it when looking, and that's the directly-c-adjacent stuff.
To be fair if I walked away from Rust for a year I'd probably be similarly lost.
The Amazon retail website (amazon.com and related versions for various countries) used the Perl Mason templating system (https://masonbook.houseabsolute.com/) to allow various teams to build web site components in a performant and secure way.
It worked quite well since it ran quickly and isolated components so that only one small change could be made without breaking other components.
What, how?
Thats bigger than windows linux llvm chromium and 5 other compilers combined according to google
Linux is a pretty small codebase compared to most proprietary codebases in large companies to be fair though.
The commands supported by `sh` are... let's keep it at "fossilized from somewhere in the 80s", and so the only alternative was perl which has a ... history of being not exactly user-friendly to code for.
[1] https://www.debian.org/doc/debian-policy/ch-files.html#s-scr...
1 - http://archive.debian.org/debian-archive/debian/dists/buzz/m...
fn eat(food: Edible) just takes an actual Edible. Afterwards the food is gone, perhaps this function stashed it somewhere, or gave it away, but you don't have it any more† so maybe it was Dropped (destroyed)
fn sniff(food: &Edible) -> Smell this time our function only wants an immutable reference to the Edible. The food isn't changed in any way by this predicate, it's still yours, and now you also know how it Smells.
fn lick(food: &mut Edible) -> Review but this function modifies the Edible via the exclusive reference. You still have the food, and now you've got a Review, but the food may be changed, perhaps irreversibly by being licked.
† If Edible is Copy then Rust will just copy it, so the caller still has it, types which are Copy are typically small, and they can't implement Drop, so if they were destroyed nothing happens anyway. An integer is Copy, a String isn't Copy, and neither is a File, or a network Socket, or whatever. You can make your own types Copy, if you want, and if they qualify.
I was referring to the `Box<dyn Trait>` one, as I'm at least 90% sure `Box<X>` passes a owned, dynamically-allocated X by reference (ie, Box<X> is a pointer to X).
If the function only wanted a reference to it, that would be &Box<dyn Bird> and then I wouldn't give up ownership by passing it to the function. But that's also a very strange thing to ask for, since we can instead pass a reference to a Bird, no need to Box it.
No, a Box<dyn Bird> is a pointer to some sort of Bird on the heap. Unless Rust has wildly changed how it implements function calls/stack frames, local variables are stored on the stack. A pointer is a reference to the thing it points to (in sense used in the phrase "pass by reference").
> then my call moves the Box<Goose> into the function, I don't still have that Goose
Yes: you passed a Box<Goose> by value, you passed the Goose it points to by reference, and you transfered ownership of both.
> are you promising to deallocate and otherwise clean up the object when you're done with it, versus are you promising that the caller can keep using it after you return.
Whether I ask for a Goose or a Box<Goose>, it's mine now. The caller no longer has it, it's not just that they shouldn't use it, they can't, the compiler won't let them. Since it's mine, it is now my responsibility as owner either clean up, give it to somebody else or explicitly leak() it.
Rust doesn't promise how exactly this is implemented, and it is likely to be different for an object of 4 bytes than for an object of 400 bytes.
It is true, though, that there are differences. With the generic, you can refer to the type again later, whereas the type is anonymous with `impl Trait`. And `dyn Trait` gives you dynamic dispatch. But in my experience there are usually some differences between the multiple ways to do something in Perk as well.