Huh, I sure think it is. I wonder what the author thinks the competition might be? Ruby has its issues for sure, but aesthetics ain't one of them - far and away my favourite out of any major language.
Huh, I sure think it is. I wonder what the author thinks the competition might be? Ruby has its issues for sure, but aesthetics ain't one of them - far and away my favourite out of any major language.
"I came across Ruby in 1998 because I was an avid reader of comp.lang.misc (ask your parents). I downloaded it, compiled it, and fell in love. As with any time you fall in love, it’s difficult to explain why. It just worked the way I work, and it had enough depth to keep me interested.
"Fast forward 15 years. All that time I’d been looking for something new that gave me the same feeling. Then I came across Elixir, a language by José Valim, that puts a humane, Ruby-like syntax on the Erlang VM."
So while he loves Ruby he's mostly moved on to Elixir, which he loves partly because of how it builds on the ideas in Ruby.
I think he meant beautiful in the conceptual sense (e.g. a beautiful algorithm) not the aesthetic sense.
Aesthetically speaking, Ruby would definitely be in my top 3 and possibly first. For me its main competition is ML-syntax languages, in particular Standard ML and F#.
Let's do a mini code challenge in the thread -- implement fizzbuzz in the most beautiful way you can, in the most beautiful language you know:
[1] https://codegolf.stackexchange.com
Off-topic, take a look at "Add a language to Polyglot" which was concluded at 194 languages, but people kept adding more: https://codegolf.stackexchange.com/questions/102370/add-a-la...
public static void main(String[] a) {
for(int n=0; n++<100;) System.out.println(new String[]{String.valueOf(n), "Fizz", "Buzz", "FizzBuzz"}[-n%3 >>> 31 ^1 | -n%5 >>> 30&2 ^ 2]);
} (defn fizz-buzz [n]
(map #(cond (= 0 (mod % 15)) "FizzBuzz"
(= 0 (mod % 5)) "Fizz"
(= 0 (mod % 3)) "Buzz"
:else %)
(range 1 n)))Edit: Here is a Racket equivalent
(define (fizz-buzz start finish)
(for-each (λ (i) (println
(cond ((= 0 (remainder i 15)) "FizzBuzz")
((= 0 (remainder i 5)) "Fizz")
((= 0 (remainder i 3)) "Buzz")
(else i))))
(range start finish)))
(fizz-buzz 1 101) (def fizzbuzz-nums (range 1 101))
(defn fizz? [n] (zero? (% n)))
(defn buzz? [n] (zero? (% n 5)))
(defn fizzbuzz? [n] (and (fizz? n) (buzz? n)))
(defn fizzbuzz [n]
(cond (fizzbuzz? n) "FizzBuzz"
(fizz? n) "Fizz"
(buzz? n) "Buzz"
:else n)))
(def fizzbuzz-list (map fizzbuzz fizzbuzz-nums))
(apply println fizzbuzz-list)But this brings up a debate I've been having with some folks. I have the memory of a gnat, so I can't keep a lot of context in my head. I prefer the previous two examples to this one, simply because with this one, I have to remember a lot more contextual vocabulary.
It's a pet-peeve of mine to pull up a source file, and then have to ping-pong around between 50 different function calls, when the entire thing could have been written linearly in fewer than 50 lines of code.
On the other hand, small functions like yours are easier to verify at a glance and move on. I haven't figured out what the right trade-off is.
Anyone else want to weigh in on this conundrum?
* Is a common idiom in the code base / same logic used in multiple places
* Has "sufficient" complexity
* Can be replaced with a good name that is generally clear with what it will achieve
For Slackwise's example, I think that the names used in the abstractions are exactly what I would use, but I also think that they're not really descriptive enough. If I wasn't the original author and thought I should refactor the names, I would probably try to choose divisible-by-3?, divisible-by-5?, and divisible-by-15? because what the hell is a fizz or a buzz anyway? Maybe you had already thought about all of this and wanted a deeper response; sorry to disappoint.
print(" ".join("FizzBuzz" if i % 15 == 0 \
else "Buzz" if i % 5 == 0 else "Fizz" if i % 3 == 0 \
else str(i) for i in range(1, 101)))
From:FizzBuzz in Python with nested conditional expressions and a generator expression:
https://jugad2.blogspot.com/2018/12/fizzbuzz-in-python-with-...
Not claiming its the best in any way, just a way that I thought of.
2. Why are you interpreting what he (or she) meant? Let them do it themselves.
3. I qualified my earlier comment as saying that it is not necessarily the best way - up front.
4. Beauty is in the eye of the beholder, and beholders vary a lot in their tastes, whether programmers or non-programmers. Like the "de gustibus" quote:
https://en.wikipedia.org/wiki/De_gustibus_non_est_disputandu...
So chill, pal.
['fizz' unless i%3] + ['buzz' unless i%5] or i for i in [1..100] 1.upto(100) do |n|
puts [ ("Fizz" if a = (n % 3).zero?), ("Buzz" if b = (n % 5).zero?), ( n unless (a || b) )].join
end module FizzBuzz
def to_fb
s = ''
s << (self % 3 == 0 ? 'Fizz' : '')
s << (self % 5 == 0 ? 'Buzz' : '')
s << self.to_s if s.empty?
return s
end
end
Integer.include(FizzBuzz)
1.upto(100) { |i| puts i.to_fb }Edit to add: Actually, now that I think about it, using method_missing would have been even better!
But the edit window had passed by the time I changed it.
(1..100).map { |i| i.modulo(15).zero? && "FizzBuzz" || i.modulo(3).zero? && "Fizz" || i.modulo(5).zero? && "Buzz" || i } #!/usr/bin/env ruby
puts((1..100).map do |n|
"#{:Fizz if (n % 3).zero?}"\
"#{:Buzz if (n % 5).zero?}"
.then
.find { |s| !s.empty? } || n
end) (1..100).each do |n|
a = String.new
a << "Fizz" if n%3 == 0
a << "Buzz" if n%5 == 0
a << n.to_s if a.empty?
puts a
end
(Disclaimer: not my code, on mobile so I stole that off GitHub)I changed it to a relatively KISS and IMO genuinely beautiful version in the parent, for others' benefits here's the version you were referring to in the above comment:
#!/usr/bin/env ruby
# frozen_string_literal: true
module FizzBuzz
Integer.include self
def self.array(enumerable = 1..100)
enumerable.map(&:to_fizzbuzz)
end
def to_fizzbuzz
"#{:Fizz if (self % 3).zero?}"\
"#{:Buzz if (self % 5).zero?}"
.then
.find { |s| !s.empty? } || to_s
end
end
puts FizzBuzz.arrayElixir (with static type analysis) - gets a bit of an edge, IMO, thanks to pipes, which are way prettier than .then:
defmodule FizzBuzz do
@spec fizzbuzz(integer)::String.t
def fizzbuzz(int) do
cond do
rem(int, 15) == 0 -> "FizzBuzz"
rem(int, 5) == 0 -> "Fizz"
rem(int, 3) == 0 -> "Buzz"
true -> inspect int
end
end
end
1..100
|> Enum.map(&FizzBuzz.fizzbuzz/1) #[0]
|> Enum.join("\n")
|> IO.puts
#[0] function variables are a very slightly "ugly
#syntax" part of the language due to erlang legacy
Other stuff that's really pretty in elixir is the first class documentation. Elixir docs are out of the box prettier than ruby docs.Compare from the official (but as a user you get these docs too):
https://ruby-doc.org/core-2.6/Array.html
https://hexdocs.pm/elixir/List.html#content
But again, it's only a bit prettier. Of course, if you try to browse both on mobile, Elixir wins handily. This is great for when you have to use the bathroom at the same time as you're in the middle of debugging and need to look up what a library module member function does, so there's some developer benefit edge too.
The IO.inspect(value, label: "label string") semantic is incredibly powerful. During debugging I often do this:
value
|> IO.inspect(label: "A")
|> do_something
|> IO.inspect(label: "B")
|> do_something_else
|> IO.inspect(label: "C")
...
This gives me full visibility over the data transformations that are happening. And removing the IO.inspect's are trivial with an IDE like atom, vscode, etc. Also the way that the BEAM handles concurrent IO means that none of those strings that I send will be interrupted by other content, which is critical to interpretable println debugging in a concurrent environment. I haven't used the debugger (or IEX.pry, whic I hear is powerful) once. # don't really know what IO.inspect is doing
# but guessing something like this?
def IO.inspect(value, label:)
puts "#{label}: #{value.inspect}"
value
end
value.pipe do
IO.inspect(label: "A")
do_something
IO.inspect(label: "B")
do_something_else
IO.inspect(label: "C")
end 1..100
|> Enum.map_join("\n", fn
int when rem(int, 15) == 0 -> "FizzBuzz"
int when rem(int, 5) == 0 -> "Fizz"
int when rem(int, 3) == 0 -> "Buzz"
int -> inspect int
end)
|> IO.puts (1..100).each { |n| { 15 => 'FizzBuzz', 3 => 'Fizz', 5 => 'Buzz' }.find { |d, s| n % d == 0 }.then { |_, s| puts s || n } } [case (n `rem` 3 == 0, n `rem` 5 == 0) of
(True, False) -> "Fizz"
(False, True) -> "Buzz"
(True, True) -> "FizzBuzz"
(False, False) -> (show n)
| n <- [1..100]
]