News for hackers. Stuff that matters.
Re:Sapper, a lightweight web framework written in Rust by Thaxll on Wednesday June 01, 2016 @01:56PM (#11816639)
The more I look at Rust the less I like the syntax, what are those? "Ok(())"
Re:Sapper, a lightweight web framework written in Rust by pornel on Wednesday June 01, 2016 @02:50PM (#11817103)
There are some eye-poking bits in Rust's syntax, but this one is not so bad.

`Ok(value)` makes an instance of the `Result` type. Imagine `struct Result Ok(some_t value);` in C.

`()` is a 0-length case of a tuple. Sort-of like `{}` in C's `int arr[] = {}`.

It's used here, because `Ok` is defined to take a value, so something must be provided. The compiler knows how to optimize out `()` completely, so the single `Result` type can be used for efficiently handling both cases returning a something||error and NULL||error.

Re:Sapper, a lightweight web framework written in Rust by pcwalton on Wednesday June 01, 2016 @02:13PM (#11816787)
() is the unit/void value. The void value isn't a concept that most languages have, so the syntax may be unfamiliar, but it's really useful and once you have it it's annoying to work with languages that don't have it.
Re:Sapper, a lightweight web framework written in Rust by nostrademons on Wednesday June 01, 2016 @02:35PM (#11816971)
It's actually fairly common in modern languages, particularly in expression-oriented languages. Haskell, Ocaml, Swift, and Scala spell it (). Python spells it None. Kotlin spells it Unit(). In Kotlin and Python, it is implied whenever you do 'return' without a value, which is a pretty handy way of bridging programmers' understanding of it when they come from older programming languages (eg. Java and C) that don't have it.
Re:Sapper, a lightweight web framework written in Rust by Jweb_Guru on Wednesday June 01, 2016 @03:02PM (#11817210)
Python's None is closer to null than unit.
Re:Sapper, a lightweight web framework written in Rust by adrusi on Wednesday June 01, 2016 @05:30PM (#11818348)
There isn't really a meaningful distinction in a dynamically typed language.

Null is a value that indicates the absence of something else that could be there instead, Unit is essentially the lack of any value. So when a python function implicitly returns None whenever it's called, that's semantically more similar to Unit than Null.

Re:Sapper, a lightweight web framework written in Rust by kazagistar on Thursday June 02, 2016 @03:46AM (#11820969)
The difference is methods. A Result or Option has methods like map that let you transform it regardless of which case it is in, while a null will always crash unless you match on it first.
Re:Sapper, a lightweight web framework written in Rust by adrusi on Thursday June 02, 2016 @08:07AM (#11821818)
In that case, do you condsider Go's nil to not be a null, since you can call methods on it that can do whatever? Or how about objective C's nil, where any messages sent to it are simply ignored?

Edit: I see now that you're talking about the difference between null and Result/Option, not the difference between null/Option and Unit, so we're talking about different things.

Semantically, a value that could be data or null is equivalent to an option type. Option types have methods, yes, but that's just a superficial convenience facility, you could implement the same thing for nullable types by writing a function:

    public static <A, B> B map(A object, Function<A, B> f) {
        if (object == null) return null;
        return f.apply(object);
    }
Re:Sapper, a lightweight web framework written in Rust by Sean1708 on Thursday June 02, 2016 @04:59AM (#11821181)
Python also has ().

    >>> type(())
    <class 'tuple'>
Re:Sapper, a lightweight web framework written in Rust by educar on Wednesday June 01, 2016 @06:30PM (#11818783)
I get what you are saying. The code is not very readable for an engineer well-versed is C-style languages.

That said, I was a systems engineer and did a lot of C++ but now don't really understand it anymore because these days it's incomprehensible to me especially after c++11/14 (and I coded in c++ for many years!).

Same goes for javascript - with es7, the language syntax is changing very much (and imo, not for the better). They just keep adding features for no reason.

I just hate that languages at some point try to behave they are some sort of library with non-stop changes :/ So, despite not liking Go syntax, I like the people behind Go. They don't want to change it too much for no reason (yes yes, we need generics). I like that philosophy.

In fact, C is pretty much the only language which has held on to it's core syntax to me.

Re:Sapper, a lightweight web framework written in Rust by lossolo on Wednesday June 01, 2016 @03:53PM (#11817592)
Or this:

pub fn from_bytes(bytes: &'a [u8]) -> IResult<&'a [u8], C<'a>> { ... }

or something like this:

fn parse_response<'a>(bytes: &'a [u8]) -> IResult<&'a [u8], C<'a>> { switch!(bytes, tuple!(be_u32, be_u32), (::CONNECT_ACTION_ID, tid) => map!(be_u64, |cid| B::new(tid, ResponseType::Connect(cid)) ) | (::ANNOUNCE_IPV4_ACTION_ID, tid) => map!(call!(W::from_bytes_v4), |ann_res| { C::new(tid, ResponseType::Announce(ann_res)) }) |

Re:Sapper, a lightweight web framework written in Rust by marquisee on Wednesday June 01, 2016 @09:47PM (#11819798)
I wouldn't take this as representative of normal Rust code. This is standard nom which I would categorize very much as a DSL of sorts for creating parser combinators. In order to understand this code you really have to understand the fundamentals of nom as the reason it is so powerful is because there is a bit of magic going on here.

Also, I knew this piece of code looked familiar. For those that wanted to see this code with whitespace, https://github.com/GGist/bip-rs/blob/master/bip_utracker/src....

Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Wednesday June 01, 2016 @04:11PM (#11817735)
You're missing a <'a> in the declaration there ;)

"from_bytes is a public function with one lifetime parameter, a. It takes one argument, a slice of u8 with the lifetime 'a, and returns an IResult, which gives back a slice of u8 with the lifetime 'a in the success case, and some type C, which is also parameterized with the lifetime 'a, in the failure case."

This is not really normal rust code; it's nom, which is a very macro-heavy DSL. There are decent upsides, and I love nom, but its downside is that it does look a bit odd.

Re:Sapper, a lightweight web framework written in Rust by Sammi on Wednesday June 01, 2016 @04:33PM (#11817912)
It doesn't look a bit odd. It looks impenetrable.
Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Wednesday June 01, 2016 @04:48PM (#11818027)
Well, without all the whitespace, it is ;)
Re:Sapper, a lightweight web framework written in Rust by andrewflnr on Wednesday June 01, 2016 @11:33PM (#11820181)
Seriously, you can't strip out the whitespace and then pretend to make reasonable critiques of readability.
Re:Sapper, a lightweight web framework written in Rust by nitrogen on Wednesday June 01, 2016 @04:25PM (#11817841)
It would be amazing if there were a parser that would translate Rust declarations into english. I think something like that exists for C, but I can't recall the name or how effective it is.
Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Wednesday June 01, 2016 @04:47PM (#11818024)
Re:Sapper, a lightweight web framework written in Rust by e12e on Thursday June 02, 2016 @03:20AM (#11820891)
It's a bit ironic that something that uses a lot of macros becomes hard to read. Even the link provided by marquisee in a sibling common seems to have almost a ratio of 2:1 of "signal noise" (or (too) densely coded meta-code) to the amount of "actual" code.

Have there been any (recent) discussions on how to make this stuff friendlier? I mean, one could always just bootstrap lisp on top of ecl[1], like clasp[2] does, and either generate rust code, or just machine code -- but even for plain rust it seems it should be possible to this stuff in a friendlier way?

I'm wondering if it wouldn't be worth it to have a more verbose syntax and/or keywords for this stuff -- it really does appear to me as a usability barrier -- not just because it's new and strange. Reminds me a bit about perl's use of "sigils" which I never quite thought made a lot of sense personally. I'm firmly in the camp that if you want more syntax than common lisp or smalltalk, you need a really good reason for every bit you add. And while I like a lot of things about rust, I'm starting to wonder if this isn't an area that really needs improving. Kind of like how C++14 tries very hard to get rid of a lot of stuff.

[1] "Embeddable Common Lisp" https://common-lisp.net/project/ecl/

[2] https://github.com/drmeister/clasp

Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Thursday June 02, 2016 @02:00PM (#11824637)
I don't think it's ironic; macros enable new syntax, so you'll see it much less than "regular" Rust code, and so it will look a little strange. What parts of that link do you think are "meta" vs "actual"? It's not like we just added syntax for the fun of it :)

"Just embed a Lisp" is very far from a "just", and, most non-lispers find Lisp very hard to read, specifically because there is no syntax.

Re:Sapper, a lightweight web framework written in Rust by e12e on Thursday June 02, 2016 @02:38PM (#11824973)
Fair enough, "just embed lisp" was a bit tounge-in-cheek. I suppose what I mean is that lisp macros, while powerful, don't need to add syntax that is jarringly different from other syntax (although they certainly can). I suppose I think that stuff like:

  fn parse_response<'a>(bytes: &'a [u8]) ->
    IResult<&'a [u8], TrackerResponse<'a>>
    {
      switch!(bytes, tuple!(be_u32, be_u32),
     (::CONNECT_ACTION_ID, tid) =>
       map!(be_u64, |cid|
         TrackerResponse::new(tid,
         ResponseType::Connect(cid))
      ) |  (...)
Appears to be very dense in very terse type and life-time information, compared to the variable names, function calls/macro expansions.

I get that it might be necessary at times, I just think it is a worthy goal to strive to make code look somewhat simple, even when doing complex things.

Example, in this case, with all the lifetimes(?) being the same(?) 'a, could perhaps the compiler infer that? Would it be more useful to make it explicit when they differ?

That kind of thing.

[ed: As or it being ironic, I see powerful constructs like macros more as a tool for making complex things simpler, not to complicate simple things.

That's what I mean when I say "macro-heavy" code being hard to read is ironic. It could of course be that this example really is complex, but it kind of strikes me as looking more "complected" than "complex".]

Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Thursday June 02, 2016 @03:47PM (#11825487)

  > I just think it is a worthy goal to strive to make code
  > look somewhat simple,
To be clear, I do as well. Some things are just inherently complex, though.

  > could perhaps the compiler infer that? 
The only reason they're added here is that they're not able to be inferred, and the reason they're all the same is that you're explicitly connecting the lifetime of each of these things.

  > it kind of strikes me as looking more "complected" than "complex".
nom is for building extremely fast, extremely low-overhead parsers. When you're trying to do stuff like that, you can't always afford convenience stuff. Consider if you had to write all the code the macros generate by hand!
Re:Sapper, a lightweight web framework written in Rust by e12e on Thursday June 02, 2016 @11:14PM (#11828064)
> The only reason they're added here is that they're not able to be inferred, and the reason they're all the same is that you're explicitly connecting the lifetime of each of these things.

Is the default of having them all be implicitly different, or unlinked, lifetimes very useful?

Re:Sapper, a lightweight web framework written in Rust by steveklabnik on Friday June 03, 2016 @12:11PM (#11831174)
If you don't write anything at all, the "lifetime elision rules" kick in: http://doc.rust-lang.org/stable/book/lifetimes.html#lifetime...

We used to only have the first of those three rules. When we added the other two, almost 90% of lifetime annotations in function declarations were able to be removed from the compiler and standard library.

Re:Sapper, a lightweight web framework written in Rust by nemaar on Wednesday June 01, 2016 @02:00PM (#11816673)
It's an empty tuple stuffed into an enum variant called Ok. The empty tuple plays the role of the traditional void.
Re:Sapper, a lightweight web framework written in Rust by dikaiosune on Wednesday June 01, 2016 @02:12PM (#11816780)
Importantly, it's the Ok variant of the Result<(), SomeError> type, which is richer than a boolean because it carries information about why/where an operation failed, not just whether it succeeded or failed. It's similar to (but not identical to):

    public void someOperation() throws SomeException { ... }
Re:Sapper, a lightweight web framework written in Rust by cfallin on Wednesday June 01, 2016 @02:23PM (#11816866)
I like to compare it to the "comma error" idiom in Go, i.e., `result, err = doStuff(...)`. The Rust prelude's Result enum is a less ad-hoc version of that.
Re:Sapper, a lightweight web framework written in Rust by yarper on Wednesday June 01, 2016 @04:24PM (#11817825)
It supports that kind of error handling too,

fn something() -> (String, String) ...

let (result, err) = something()

It's just that Result is preferable because you can pattern match on it

Re:Sapper, a lightweight web framework written in Rust by kazagistar on Thursday June 02, 2016 @03:52AM (#11820991)
That would be

    fn something() -> (Option<String>, Option<String>)
Because the Rust types aren't nullable by default. But that more clearly demonstrates that Result types are better since they enforce that the error and result are mutually exclusive.
Re:Sapper, a lightweight web framework written in Rust by yarper on Thursday June 02, 2016 @11:47AM (#11823442)
agreed!
Re:Sapper, a lightweight web framework written in Rust by dikaiosune on Wednesday June 01, 2016 @02:25PM (#11816881)
Right, and the Rust result also produces a compile-time warning (which can be escalated to an error) if the value isn't checked.