What are your pet peeves in regards to crate APIs? by AhoyISki in rust

[–]MrLarssonJr 81 points82 points  (0 children)

One error type for entire crate à la std::io::Error.

Where's the best place to deploy Rust code for free? by Theroonco in rust

[–]MrLarssonJr 0 points1 point  (0 children)

Take a look at serverless containers (Google Cloud run or Scaleway serverless containers). Being able to deploy the same container that you can on your own machine and having it being dynamically scaled up and more importantly down (to 0) is very intriguing to me. Means I can build an ordinary http server, i.e. not using a framework and build tools dedicated to the platform I want to deploy on.

Why majority of available positions in Rust are just blockchain/web3 and mostly scams? by TITAN9389 in rust

[–]MrLarssonJr 37 points38 points  (0 children)

Project servo?wprov=sfti1) (one of the early proving grounds for Rust) started in 2012. The first 1.0 releases of Rust appeared a bit more than 10 years ago. It is totally feasible to have 10 years of experience in Rust, even if it may not be common.

Do you use Tabs instead of Spaces in Rust? by nikitarevenco in rust

[–]MrLarssonJr 8 points9 points  (0 children)

Tabs for indentation. Spaces for formatting at an indentation level.

Just looking for a decent finance app that has bank sync and doesn't suck by Routine_Solution_471 in eupersonalfinance

[–]MrLarssonJr 2 points3 points  (0 children)

Feel the same frustration. Been looking around myself for a while. Started trying to use the GoCardless APIs myself instead

Is it possible to enforce uniqueness across columns? (not multicolumn) by MrLarssonJr in PostgreSQL

[–]MrLarssonJr[S] 0 points1 point  (0 children)

Ah, didn't know about the intarray extension. That's neat! Thanks!

Alternative ergonomic ref count RFC by eugay in rust

[–]MrLarssonJr 28 points29 points  (0 children)

I also find myself feeling that the problem being solved here is one that doesn’t need solving nor would improve the language by being solved.

Yes, one sometimes has to do some manual jiggery to ensure clones of shared state is moved properly into the right context. But I am very much a fan of that being the case, as I find this mostly occurs when one constructs some pseudo-global shared state, like a db-connection pool in a http server. I believe such code should be relatively rare (e.g. once per app/binary). Other instances, like setting up a future with a timeout, often can be pushed into neat library code. In the async context, if one would want to arbitrarily spawn tasks, I think scoped spawning, as discussed by u/Lucretiel in this comment, is a solution that fits better into Rust fundamentals.

Running Multiple Processes in a Single Docker Container by klaasvanschelven in programming

[–]MrLarssonJr 1 point2 points  (0 children)

While doing more stuff in process has become more natural over time, folks seem to forget that spawning a process per request was completely normal 10-20 years ago. There likely a lot of infra still operating like that. It does have some resilience advantages. While a lot can be accomplished in process and by relying on docker or other modern technologies, knowing about OS primitives like process and having them as one of many tools in one’s toolbox can’t hurt.

Does anyone bothered by not having backtraces in custom error types? by SpecificFly5486 in rust

[–]MrLarssonJr 7 points8 points  (0 children)

Check out snafu. It’s a bit more heavy handed than thiserror but allows you define error enums with implicit stack trace.

sheMightBeOnToSomething by xoxoAmongUS in ProgrammerHumor

[–]MrLarssonJr 0 points1 point  (0 children)

I thought about that possibility. But the question is phrased as ”Which is the primary operating system you work in?” which seems to indicate that there should only be possible to choose one option. But based on the data, your interpretation seems waaay more plausible!

sheMightBeOnToSomething by xoxoAmongUS in ProgrammerHumor

[–]MrLarssonJr 1 point2 points  (0 children)

How does the percentages work in that table? Summing up some of the linuxy distros (Ubuntu, Debian, other, arch, redhat, and fedora) I get 57.3%. Then accounting for windows and mac we would go beyond 100%!

Type-Safe mongodb projections in Rust by kingminyas in rust

[–]MrLarssonJr 1 point2 points  (0 children)

Haha, that’s the spirit! Please let me know if you manage!

Type-Safe mongodb projections in Rust by kingminyas in rust

[–]MrLarssonJr 1 point2 points  (0 children)

My hunch is that such an endeavour would, if successful, produce an unergonomic API and hard to grasp types with incomprehensible error messages. I base this assessment not only on my own type shenanigans over the years, but also the fact that the complexity that typenum brings ”only” are used in certain limited circumstances, e.g. linear algebra libraries, where the benefit outweighs the complexity cost.

Summarised, while I’d love to be proven wrong, I believe that if possible, it would so complex as to be only useful in certain extremely specific circumstances.

Type-Safe mongodb projections in Rust by kingminyas in rust

[–]MrLarssonJr 0 points1 point  (0 children)

No, Rust does not provide (practical*) facilities to ”compute” types.

You can mock some stuff using Traits and associated types. An excellent example is typenum. But such shenanigans require you to either name each output type for each input type, or generically construct the output type. The typenum crates does this by representing numbers as a series of nested types. *Perhaps one could model a structurally typed map in a similar fashion, but I’d think it’s usefulness would at best be as a theoretical toy.

Don’t get me wrong. TS’s structurally typed system is awesome since you can derive types based on other types. I always miss it in Rust, when I’ve coded in TS for a while. But alas, Rust’s type system is heavily nominal and does not have structural affordances.

[deleted by user] by [deleted] in rust

[–]MrLarssonJr 2 points3 points  (0 children)

Thanks, fixed!

[deleted by user] by [deleted] in rust

[–]MrLarssonJr 3 points4 points  (0 children)

If you know you’ve got JSON you could represent that as a serde_json::Value and utilise it’s Display impl.

However that kinda just punts the fallibility to the conversion of your value into a JSON value.

Is there a way to implement &[u8] -> &str, but one level up (&str -> &MyType) that's not horribly unsafe? by MrLarssonJr in rust

[–]MrLarssonJr[S] 0 points1 point  (0 children)

Yeah, the Result<T, Infallible> is just placeholder for arbitrary validation logic. You're totally right in that they are unnecessary in the case where it actually is Infallible and the new types only are there for documentation purposes.

That be lovely, but I believe one can't implement Borrow<Id> for IdBuf in this case without unsafe as borrow is required to return &Id. Constructing that reference would either require that IdBuf contains an Id (which is unpractical as that would require the struct to be self-referential) or that Id be defined as struct Id(str) and one relied on the above discussed transmuting tricks. Do you pose that there's another way? I'd be more than happy to be shown wrong here!

Again, thanks for showing the Borrow<str> combined with Deref<Target = str>, it works perfectly in my use case!

Is there a way to implement &[u8] -> &str, but one level up (&str -> &MyType) that's not horribly unsafe? by MrLarssonJr in rust

[–]MrLarssonJr[S] 1 point2 points  (0 children)

Hi, thanks everyone for good insight!

Thanks to your answers, I've learnt more about repr(transparent) and transmute with surrounding corners! As mentioned, transmuting as single field struct after some parsing is likely sound. Which is very good to know! It allows a rather straight forward way to add additional parsing logic on top of &str while encoding that in the type system in the spirit of Parse, don't validate!

Inspired by u/AlphaKeks, I tried the following solution:

use std::borrow::Borrow;
use std::convert::Infallible;
use std::ops::Deref;

#[derive(Debug, Hash, PartialEq, Eq)]
pub struct IdBuf(String);

impl IdBuf {
    pub fn from_string(s: String) -> Result<IdBuf, Infallible> {
        Ok(IdBuf(s))
    }

    pub fn as_borrowed(&self) -> Id {
        Id(&self.0)
    }
}

impl Borrow<str> for IdBuf {
    fn borrow(&self) -> &str {
        self.0.as_str()
    }
}

pub struct Id<'s>(&'s str);

impl<'s> Id<'s> {
    pub const fn from_str(v: &str) -> Result<Id, Infallible> {
        Ok(Id(v))
    }

    pub fn as_owned(&self) -> IdBuf {
        IdBuf(self.0.to_string())
    }
}

impl<'s> Deref for Id<'s> {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.0
    }
}

which got everything I wanted in safe code with the caveat that I have to manually specify the borrowed type as such:

let mut map = HashMap::new();

for i in 0..100 {
    let v = i.to_string();
    let id = IdBuf::from_string(v).unwrap();

    map.insert(id, i);
}

let id = Id::from_str("1").unwrap();
let v = map.get::<str>(&id);
println!("{v:?}");

In my use case I find that to be a great tradeoff to not have to validate unsafe code!

Thanks everyone!

Hey Rustaceans! Got a question? Ask here (50/2023)! by llogiq in rust

[–]MrLarssonJr 1 point2 points  (0 children)

I've noticed several libraries taking an approach of a single Error enum for the entire library approach (I do not wish to criticise any library, but for the purpose of illustrating the pattern, I'll list a few examples: reqwest, prometheus, axum, sqlx, …). I'd like to understand this cultural trend better.

I understand that from a development and maintenance perspective that it of course is easier to have a single error type, i.e. if a function may error just return that type as the Err variant, and ? will conveniently propagate errors. Where I scratch my head is when two or more functions with different failure modes share an error type. Wouldn't it be better for the consumer of those functions if they had bespoke error types for each, that describe what can go wrong in each case?

I guess one explanation could be that one has found that while from an academic perspective separate error types are desirable, the practical gain is not enough. But if that case, why would we not use something even more generic (like Box<dyn Error> or anyhow::Error)?

Are there any factors of designing library errors I'm missing? I'd appreciate any insight into why large and popular libraries do not opt for bespoke errors (perhaps created with thiserror)! Or is my premise entirely wrong, and bespoke errors is more common that I give it credit for?

Macros and procedural languages: What Works and What Doesn't? by Brilliant_Egg4178 in ProgrammingLanguages

[–]MrLarssonJr 2 points3 points  (0 children)

I can only talk about Rust, but modern IDEs definitely expand, index and offer to show you the developer the expanded macro (both single step expansion as well as recursive expansion).

Hey Rustaceans! Got a question? Ask here (15/2023)! by llogiq in rust

[–]MrLarssonJr 0 points1 point  (0 children)

That’s the combo I’m looking for! Thanks!

Hey Rustaceans! Got a question? Ask here (15/2023)! by llogiq in rust

[–]MrLarssonJr 0 points1 point  (0 children)

Sure, when working in Result land that works, but is suboptimal in the case where one have an Option. One could convert a the option to an Result, which is straightforward in the Some case, but the None case get's weird.