Git Product home page Git Product logo

tightness's People

Contributors

pablomansanet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

iq-scm

tightness's Issues

Problem with flexibility

Hi! I've read your post and think that this is a pretty cool idea. But I also think that there are some things that could be better. For example, when I tried to use this lib in my project, I found myself doing something like this:

use tightness::bound;

pub struct User {
    pub name: UserName,
}

bound!(UserName: String where |s| !s.is_empty());

impl User {
    fn new(name: &str) -> Result<User, &'static str> {
        let name = name.trim().to_string(); // no need to make programmer always trim the string himself
        let name = UserName::new(name).map_err(|_e| "name is empty")?;
        Ok(User { name })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert!(matches!(User::new("   "), Err("name is empty")));
        assert!(matches!(User::new(" something  "), Ok(_)));
    }
}

There's two problems:

  • I want to mutate my value first. The data can come from different sources, i.e. from a HTTP request or from some CLI input. Implementing this mutation everywhere seems to make code clumsier.
  • I want to be able to return my own error. Again, if data come from different sources, with current approach one must do .map_err everywhere.

All of this things tear the domain logic of the type into different places, which is not good. The code above solves some of this problems, but still if I want to mutate the name somewhere else, I need to convert the error there. And, of course, the same thing applies to manual struct creation.

How do you thing, is it possible to expand the macro so it allows user to mutate the value and return another error? Would be happy to help with that, although I have no experience writing macros.

And one side note: is it possible to somehow integrate this thing with serde if internal type implements Serialize and Deserialize? I would be awesome if the validation could be handled during serialization.

Meaning of validity after a mutator panic

The protecting code of mutators does not protect the (implicit) panic exit point with assertions of the invariant holding. This makes it possible to observe an instace of a tightness-defined type whose invariant is in fact violated.

bound!(Letter: char where |c| c.is_alphabetic());

struct Observer(Letter);

impl Drop for Observer {
    fn drop(&mut self) {
        if !self.0.is_alphabetic() {
            println!("Woah there");
        }
    }
}

let mut obs = Observer(Letter::new('a').unwrap());
obs.0.mutate(|l| *l = '0'); // Not, in fact, alphabetic

// Prints: Woah there

However, for usual validity invariants such as those upheld by str or NonZeroU8 etc. even this kind of observation is forbidden. This may be a concious design decision as the only 'correct' way to handle this would be an immediate program abort instead of a usual panic. For the fallback mutate_or it is at least theoretically possible to handle it correctly while continuing to panic but you need to assign to self through a drop-guard instead of a code path that is never reached on panic unwinding.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.