Live data from Hacker News

Why your first Rust FizzBuzz implementation may not work

chrismorgan.info

41–50 of 139 posts

Re: Why your first Rust FizzBuzz implementation may not work

#41
post #28

For what it's worth, String in Rust is similar to StringBuffer in other languages. You can append to a String; you can't append to a slice, which always represents a fixed view. A slice has storage that is borrowed from somewhere else, but it itself does not have its own storage. When you type `"foo"`, you are creating "static" storage (in the binary) and the slice is borrowed from that fixed-position location in mem…

But shouldn't they (String and slice) have some common super type to make this all easy to use?

Re: Why your first Rust FizzBuzz implementation may not work

#42
post #41
post #28

For what it's worth, String in Rust is similar to StringBuffer in other languages. You can append to a String; you can't append to a slice, which always represents a fixed view. A slice has storage that is borrowed from somewhere else, but it itself does not have its own storage. When you type `"foo"`, you are creating "static" storage (in the binary) and the slice is borrowed from that fixed-position location in mem…

But shouldn't they (String and slice) have some common super type to make this all easy to use ?

Yes. It's a design bug that String and slice don't share a common trait and that `.as_slice()` is common simply to use slice methods.

I expect that to be fixed before 1.0.

Re: Why your first Rust FizzBuzz implementation may not work

#43
post #41
post #28

For what it's worth, String in Rust is similar to StringBuffer in other languages. You can append to a String; you can't append to a slice, which always represents a fixed view. A slice has storage that is borrowed from somewhere else, but it itself does not have its own storage. When you type `"foo"`, you are creating "static" storage (in the binary) and the slice is borrowed from that fixed-position location in mem…

But shouldn't they (String and slice) have some common super type to make this all easy to use ?

Also, the location of storage is slightly more visible (in general) in Rust than in other languages.

I have personally found this to be pretty clarifying, because as much a we may like to abstract over it, the location of storage often worms its way into the programming model even in HLLs.

Re: Why your first Rust FizzBuzz implementation may not work

#44
post #34
post #31

Earlier quoted context omitted.

Weird to see this mix of a very imperative for-range iterative loop with a very functional pattern match, which makes it look similar to an SML or OCaml solution to FizzBuzz. I guess this is the definition of multi-paradigm right here. Will Rust's type checker warn you of a non-exhaustive pattern match?

Here's the same approach in F# without the different types of String; therefore, easier to get more functional. let fizzbuzz num = match num % 3, num % 5 with | 0,0 -> "FizzBuzz" | 0,_ -> "Fizz" | _,0 -> "Buzz" | _,_ -> num.ToString() [1..100] |> List.map fizzbuzz |> List.iter (fun (s:string) -> printfn "%s" s)

Nice F# snippet! This just looks so simple and elegant. As another approach, the "enum" types the OP mentions map to discriminated unions in F#.

FWIW your final wildcard match can be (modestly) simplified to just

  | _ -> num.ToString()
and the last line can be distilled to just

  |> List.iter (printfn "%s")

Re: Why your first Rust FizzBuzz implementation may not work

#46
post #41
post #28

For what it's worth, String in Rust is similar to StringBuffer in other languages. You can append to a String; you can't append to a slice, which always represents a fixed view. A slice has storage that is borrowed from somewhere else, but it itself does not have its own storage. When you type `"foo"`, you are creating "static" storage (in the binary) and the slice is borrowed from that fixed-position location in mem…

But shouldn't they (String and slice) have some common super type to make this all easy to use ?

I don't think a common ancestor is how you want to do this. Instead, I'd encapsulate the common behavior in a trait (a.k.a. an interface, in other languages), and then write functions that accept any parameters that implement that trait. In Rust, you can do this even on "built-in" types like strings. For an example, see the `print_me` function below, which operates on both string types using a trait that I've defined myself.

  trait WhatIsThis {
      fn what_is_this(self);
  }

  impl WhatIsThis for String {
      fn what_is_this(self) {
          println!("'{:s}' is a string!", self);
      }
  }

  impl WhatIsThis for &'static str {
      fn what_is_this(self) {
          println!("'{:s}' is a string slice!", self);
      }
  }

  fn print_me(me: T) where T: WhatIsThis {
      me.what_is_this();
  }

  fn main() {
      print_me("Blah blah blah");
      print_me("Yada yada yada".to_string());
  }

Re: Why your first Rust FizzBuzz implementation may not work

#47
post #45

In the contrived Python example, FizzBuzzItem is only called if the result is a number (not in any of the modulo 0 cases) - is that intended? I can see that it works, but it's breaking the analogy for me with the Rust code.

Whoa, that was indeed a mistake. Sorry about that. Fixed.

Re: Why your first Rust FizzBuzz implementation may not work

#48
post #46
post #41

Earlier quoted context omitted.

But shouldn't they (String and slice) have some common super type to make this all easy to use ?

I don't think a common ancestor is how you want to do this. Instead, I'd encapsulate the common behavior in a trait (a.k.a. an interface, in other languages), and then write functions that accept any parameters that implement that trait. In Rust, you can do this even on "built-in" types like strings. For an example, see the `print_me` function below, which operates on both string types using a trait that I've defined…

And I expect virtually all of the methods on slice to be available on String before long. I think it's a bug that this isn't the case today.

It's already possible to have a function take "either a String or slice" generically:

    def print_me(me: T) where T: Str {
        println!("I am '{:s}'", me.as_slice());
    }
The overall ergonomics of this (or at least, the well-documented idioms) will certainly improve in the coming months.

Re: Why your first Rust FizzBuzz implementation may not work

#49
post #31
post #20

Putting the String issue aside, I just wanted to show the beauty of pattern matching. for i in range(1i, 101) { match (i % 3, i % 5) { (0, 0) => println!("Fizzbuzz"), (0, _) => println!("Fizz"), (_, 0) => println!("Buzz"), _ => println!("{}", i), } } -- edited: removed `.to_string()`, thanks chrismorgan

Weird to see this mix of a very imperative for-range iterative loop with a very functional pattern match, which makes it look similar to an SML or OCaml solution to FizzBuzz. I guess this is the definition of multi-paradigm right here. Will Rust's type checker warn you of a non-exhaustive pattern match?

Rust was first conceived by an avid Ocamler, and it was originally implemented in Ocaml too. Although the pot has been stirred quite a bit since those early days, the influence still remains, including the expression heavy programming style, pattern matching, 'let's, HM inference, and `var: T` declaration syntax. Whilst Rust is quite procedural and (you rarely use recursion), it often feels quite functional due to those things.

Re: Why your first Rust FizzBuzz implementation may not work

#50
post #7

Earlier quoted context omitted.

sure, but when you're implicitly comparing code segments (by placing them next to each other), you should at least make the effort to make them more the same, instead of pointing out that one language is missing a feature used in the other language, especially when this claim is false. the formatting can of course be improved: for i in range(1, 101): print('FizzBuzz' if i % 15 == 0 else 'Buzz' if i % 5 == 0 else 'Fiz…

yeah, no one writes python like this.

I've seen it quite frequently and kindof like it because it doesn't introduce any state that could leak out or get mutated from somewhere else. Although the ternary operator doesn't make as much sense in python as in other languages since there is no const keyword, otherwise that's what the ternary operator is usually used for.
Post reply on HN