Ruby Community

Keynote: Keep Ruby Weird

Keynote: Keep Ruby Weird

by Yukihiro "Matz" Matsumoto

Summary of Keynote: Keep Ruby Weird

The keynote speech by Yukihiro Matsumoto, affectionately known as Matz, at the Keep Ruby Weird 2018 conference focuses on the unique aspects and complexities of Ruby's keyword arguments, introduced in Ruby 2 to enhance the language's functionality.

Key Points Discussed:

  • Introduction to Ruby's Weirdness:

    • Matz highlights the quirky nature of Ruby and discusses how the community embraces this weirdness.
  • Keyword Arguments in Ruby 2:

    • Matz explores the introduction of keyword arguments in Ruby 2, explaining their implementation and how they enhance code readability and usability.
    • He compares Ruby's keyword arguments to those in other programming languages like Python, Smalltalk, and Swift, pointing out the unique attributes of each language's handling of keyword arguments.
  • Background:

    • The talk reflects on Ruby's evolution since its inception, particularly the changes introduced with Ruby 1.9 that paved the way for keyword arguments. These changes included expanded hash arguments and simple hash syntax.
  • Syntax Examples:

    • Matz provides examples illustrating the correct usage of keyword arguments, explaining common behaviors and potential pitfalls when calling methods including keyword arguments.
    • He clarifies confusing behaviors linked to argument definition, such as how keyword arguments interact with normal arguments.
  • Challenges and Trade-offs:

    • Matz discusses the difficulty of maintaining compatibility when introducing changes to the language and addresses concerns over confusing language features versus breaking existing code.
    • He presents three potential future options for managing keyword arguments:
    • Keep the existing keyword arguments as they are, despite their oddities.
    • Introduce a new structure, such as a 'keyword hash', to clearly distinguish keyword arguments from regular hashes.
    • Fully separate keyword arguments from normal arguments to eliminate confusion.
    • Each option has its pros and cons, mainly around compatibility and usability.
  • Community Engagement:

    • Matz asks the audience to express their opinions on the options presented, emphasizing the importance of community feedback in the evolution of programming languages.
  • Conclusions:

    • The talk emphasizes the significance of compatibility in language design, avoiding unnecessary breakages that could frustrate users.
    • Matz recognizes that while improvements and innovations in Ruby are necessary, maintaining a stable environment for users is crucial for the language's ongoing success and community support.
    • Ultimately, he encourages the community to explore Ruby’s idiosyncrasies and continues to advocate for a collaborative future that keeps Ruby's spirit alive, stating, "Play with Ruby, find the weird things, keep Ruby weird."

In summary, Mats reiterates that the evolution of Ruby must balance novelty and complexity with user needs, aiming for a sustainable and engaging programming environment.

00:00:09.170 So, we're going to start off today with our keynote. Now, I am not the keynote today.
00:00:14.809 Every year we try to get Matz to speak.
00:00:22.279 Welcome to Keep Ruby Weird! Every year, like
00:00:29.359 we weren't sure which year we were going to end this, so we actually just recorded Matz saying 'Welcome to Keep Ruby Weird' and then a whole bunch of years after that, so that we could play it each year.
00:00:38.250 Now, this year, we wanted to try and get Matz to record something special for us so that we could play it for the very last year; but we weren't able to. Unfortunately, we're just going to have to do it live.
00:00:51.480 Alright, we're going to play the little laptop dance here because since this is a surprise, we did not test his equipment. So, bear with us.
00:00:57.210 Morning everyone! I was not supposed to be here maybe, but yeah, this is the conference. Keep Ruby Weird. It should work.
00:01:09.000 Okay, it's Ruby weird. What's your opinion? [Audience response] Weird? Yes? Oh no, yes, okay.
00:01:20.240 Ruby is neutral. Ruby is only abusable so that Ruby, which is weird, because we're weird.
00:01:28.400 Witness in our mind, so we are weird. We program Ruby weirdly. So, the Ruby is weird. But actually, I admit some parts of it are weird.
00:01:39.170 So today I'm going to talk about this weird thing. The weird thing is the keyword arguments.
00:01:45.830 In Ruby 2, which was released in 2013, which is the 20th anniversary of the Ruby language, we introduced keyword arguments.
00:02:01.210 In cubed Eggman's, we can look like this system with something called comments. But when we failed, we returned an exception.
00:02:11.989 Instead of... you know... so that we can provide the keyword arguments like options.
00:02:18.100 There are many languages that have keyword arguments as well, like how Python has keyword arguments, Smalltalk, C, and Swift, for example.
00:02:25.370 Each language is different; for example, in Python, they don't provide the special kinds of keyword arguments.
00:02:29.799 Every argument can be a keyword argument in Python, like this: def foo(a, b, c) defines the arguments named a, b, and c.
00:02:37.329 So that you can call those functions by providing the name of the argument so you don't have to specify any keywords in the method definition.
00:02:49.419 You can just call them by the name of the arguments, so we can call it like this: foo(c=2, b=3).
00:02:56.380 That makes a=1, b=3, and c=2 because c wasn't assigned and 3 is assigned to b, right?
00:03:05.639 You understand the ball. So this is quite uniquely Python programming I have written.
00:03:12.510 In Smalltalk, the keywords are part of the message or method name.
00:03:17.379 Like this: you can put the number 42 at the position 0, so that that works like a new array at index 0 equals 42.
00:03:24.549 In this program, the 'put' is a part of the method name. We often call it a put–colon notation.
00:03:32.260 This is the method name. In Smalltalk, these kinds of keywords are very crucial; they are mandatory in the language specification.
00:03:40.040 This characteristic of method names is inherited by Objective-C and Swift. But in Ruby, keyword arguments merge at the bottom of the arguments.
00:03:48.770 So you can, like, call a method to print the arguments when you call this method with the keyword argument.
00:03:56.200 You can just print the hash. Let me explain the background in Ruby version 1.9.
00:04:03.639 We introduced two things: one is a simple hash, and the second is the expanded hash in arguments.
00:04:10.850 Simple hash means the hash looks like this: :foo => 1, :bar => 2, instead of the hash with the arrow symbol, which is a simplified version of the symbols as keys.
00:04:22.350 Expanded hash arguments means like this: instead of writing the first column of the hash, we can write the first column inside the braces.
00:04:30.670 So we introduced these things to mimic the keyword argument.
00:04:36.900 In Ruby 1.9, we could do some kind of keyword argument as an optional argument, then document keywords like using Mirage, or something like that.
00:04:45.200 This is better. You know, this kind of manual parsing keyword argument is contained.
00:04:52.070 So, we introduced keyword arguments in Ruby 2 to avoid manual parsing.
00:05:00.230 For example, to implement the previous one monotonic argument like this, instead of writing this one in Ruby 2, we can do it like this.
00:05:09.120 Much better, but still weird because what should happen?
00:05:17.600 We define the method 'm' with a mandatory argument a and a keyword argument with a default value of 10.
00:05:27.910 Then we print the argument a and the key value.
00:05:35.700 So when we did 'm key:5', what shall we get? Yes, because this is the hash.
00:05:45.100 So this hash is assigned to a, and because we have the optional key, the default value is given, so we get the hash and 10.
00:05:56.670 Yes, it's easy, right?
00:06:03.679 So then what would happen when we called this with 'h'?
00:06:12.780 It happens like this, because the keyword argument is the last, in the argument list.
00:06:19.490 So they will be considered as the keyword hash. This means the keyword argument is used, then key will be 5.
00:06:29.390 What should happen? Yes, okay.
00:06:35.000 We have the optional argument, which defaults to an empty hash; then the keyword argument defaults to 10.
00:06:44.100 So when we call 'key:42', what should happen?
00:06:50.900 Anyone? What do I do for the tank?
00:06:57.110 The answer is like this, because the keyword arguments were binding before the keyword optional arguments.
00:07:05.320 So, this treats it as a real keyword argument, so the key will be 42.
00:07:11.610 Then we don't have the optional argument; the default value is used, so we get 42.
00:07:20.500 Yeah, it's easy, right? So, what will happen when we provide the empty hash as a keyword argument?
00:07:36.020 The answer is empty without the correct argument.
00:07:44.199 The reason is that when expanding the empty keyword has vanished.
00:07:52.740 Because it's empty, right? And then we have the only one empty hash as part of the keyword arguments.
00:08:01.630 This allows Ruby to interpret this as if it were optional arguments, so 42 is assigned.
00:08:13.150 The keyword arguments were empty, so it's kind of insane.
00:08:21.810 It works well most of the time, but we have some weird corner cases, and it's kind of confusing.
00:08:36.050 I can say it is a half-baked solution at most.
00:08:48.350 The Ruby design or the design of anything, including programming languages, is kind of difficult.
00:08:58.320 We have a lot of constraints and restrictions, and the biggest one is compatibility matters.
00:09:05.820 So is it tempting for us, the language designers, to fix the errors?
00:09:16.520 Like today, but changing existing behavior might upset existing software, and that does not make users very happy.
00:09:28.010 For example, in the age of Ruby 1.8 and 1.9, I had to introduce some instability to the language because of the Unicode support.
00:09:38.510 You have to migrate your application from Ruby 1.8 to Ruby 1.9. In some cases, this was a burden.
00:09:53.029 Some people kept using Ruby 1.8 for four years, maybe five, causing some community division.
00:10:01.480 The Python community had a similar division with Python 2 and Python 3 for more than ten years.
00:10:10.750 They declared the end of life for Python 2 in 2020, two years ahead of today.
00:10:25.010 Python 3 was released probably 15 years ago. That led to nearly 20 years of community division—quite unfortunate and a tragedy.
00:10:37.030 And then there's Perl 5/6—totally different programming language. Anyway, we had some kind of tragedy in many programming language communities.
00:10:45.390 You don't want to break your code, you know; you love to upgrade your software for your language.
00:10:51.820 But then, you don't want to fix or modify your application just to upgrade your language, while you also dislike confusing behavior.
00:11:01.550 So now, which do you hate more: the breakage or the confusing behavior?
00:11:11.590 This is the trade-off. The ability to maintain stability is very significant in the sense that even a small change could break your software.
00:11:20.390 For example, we have this 'palm' method which takes a hash as the argument.
00:11:28.830 But this hash can include 10 to 11, which we map the file descriptor, where the key is not a symbol—this cannot be the keyword arguments.
00:11:43.090 Or like this example is a very boilerplate example of creating elements of an HTML file—it's kind of a DSL.
00:11:52.900 It takes the name and the attributes, and it’s quite easy.
00:12:02.020 But if you want to add a new keyword argument, 'children', to express the children of the HTML tree.
00:12:11.610 This time, this HF is not a keyword argument, so we run into an argument error.
00:12:19.960 We could have compatibility errors unexpectedly when we try to fix anything.
00:12:27.980 So, what shall we do? We have several options. I will explain three options for keyword arguments.
00:12:35.210 The first one is keeping keyword arguments weird as they are.
00:12:41.590 The second option is to introduce something like 'keyword hash'. The third one is to totally separate keyword arguments.
00:12:51.080 Let me explain one by one. The first option is keeping keyword arguments weird as they are. There are pros and cons; it’s a trade-off.
00:13:00.390 Since we don't change anything, we won't have any compatibility issues. This is great, but we have the drawbacks.
00:13:09.590 Keeping the confusing behaviors can be amusing but it's still confusing.
00:13:18.740 The second option is introducing a 'keyword hash', which means the expanded hash arguments will be keyword arguments.
00:13:27.080 This is an example: take the keyword arguments. In the document list, you have keywords and not keywords.
00:13:35.770 The second form is to use the hash wrapped in braces, which would not be a document.
00:13:44.890 We will prohibit non-keyword expanded hashes as arguments, meaning you'll see an error if you do not use the proper syntax.
00:13:53.280 The difference between the current behavior and that behavior is minimal, making it easier to implement and the transition easier.
00:14:02.570 This is simpler argument delegation, which means delegating keyword arguments to different methods.
00:14:10.470 Currently, we do argument plotting and take the blocks as arguments, then delegate these arguments and blocks.
00:14:18.599 But with separate keyword arguments, we would need to delegate keyword arguments as well.
00:14:27.020 But, in my opinion, two things is annoying, three things are too much.
00:14:34.580 This option has compatibility issues, especially with known keywords and expanded hashes.
00:14:43.580 Any behavior change would cause errors in certain occasions, especially with expanded hashes.
00:14:49.720 Keyword hashes can leak; so the 'foo' which has its keyword hash assigned to the variable 'kW'.
00:15:01.360 Calling with that keyword hash returns one. It's confusing, but I think it's total for most users.
00:15:08.860 The biggest drawback for this option is how to optimize it. You have to allocate one hash per call when you can't use the keyword arguments.
00:15:21.070 But perhaps it can be room for optimization. This kind of keyword hash requires a hash object in your software; you must allocate one hash for every call.
00:15:36.000 The last option is introducing separated keyword arguments. The keyword arguments do not mix with normal arguments.
00:15:43.829 With this, we prohibit using expanded hashes as keyword arguments, improving the behavior.
00:15:50.170 The advantage of this option is the most sane behavior; we can eliminate confusing behaviors of the current keyword arguments.
00:15:57.799 The behavior is more consistent, and room for optimization exists. However, it has significant drawbacks.
00:16:02.700 The compatibility issues and the behavior change will be major when we select this option.
00:16:10.390 The argument delegation must be altered accordingly.
00:16:15.410 So there you have three options: keep keyword arguments weird; introduce keyword hash; or separate keyword arguments altogether.
00:16:23.750 Do you understand the three options? Yes?
00:16:31.800 Okay, think about them for 30 seconds.
00:16:38.260 These are the four options: keep the current behavior unchanged; introduce a keyword hash for distinguishing hashes as keyword arguments.
00:16:47.180 Finally, the third option is to separate keyword arguments altogether.
00:16:56.330 The trade-offs are as follows: the first option allows us to not change anything to maintain compatibility but keeps the confusing behavior.
00:17:03.050 The second one solves many of the confusing behaviors but is somewhat primitive.
00:17:10.120 The third option is more sophisticated and complicated to implement, but it offers optimization potential.
00:17:20.800 These three options are essential to consider.
00:17:28.680 I’d like to hear your opinion! If you prefer the first option, raise your hand!
00:17:36.580 If you prefer the first option: unchanged keyword arguments, raise your hand!
00:17:42.240 Maybe a third of the users are interested? Or more?
00:17:51.430 Thank you! What about the second option?
00:17:59.520 One, two, three! A very few votes, not more than 10%.
00:18:04.650 Okay, how about the last one? Raise your hand!
00:18:12.890 Most of you like the changes. I expected you to be courageous in this matter.
00:18:22.310 Thank you! This input is valuable for me.
00:18:35.060 In summary, compatibility is pretty important. If you use your language or library, you know how third-party things can break compatibility.
00:18:43.150 You'll be punished for no reason, and that's quite a pain, so don't do that unless you have a very strong reason.
00:18:56.460 Changes are tempting, but it might tempt me to break the language every day.
00:19:07.510 I feel I can improve the Ruby language significantly, but I don’t want to impose that on you.
00:19:16.920 Compatibility is about designing how you build your software. I design my language for you.
00:19:29.300 You are users of my language. You use it in many gems and applications. It's a layered structure.
00:19:43.300 The higher layer authors cannot punish their users for no reason. It might be tempting, but don't do it without valid reasons.
00:19:56.640 Though we have constraints, restrictions, and historical reasons for the weird keyword arguments, we are still committed to fixing those.
00:20:05.360 We can address the keyword weirdness by understanding the drawbacks and providing migration paths to the future.
00:20:18.320 We'll keep moving forward, as Ruby is not just a language; it's a community consisting of users and frameworks.
00:20:34.670 Without users, Ruby cannot be Ruby—it's all about you.
00:20:41.290 If no one uses Ruby, there is virtually no Ruby at all.
00:20:53.580 Therefore, the Ruby community has to provide attractions. We need to make our language better.
00:21:01.910 We need to attract people with tools, gems, frameworks, use cases, or posts. It’s crucial.
00:21:13.740 Punishing users with compatibility breaks can drive away motivation.
00:21:23.420 Conversely, positive changes can attract interest to a better language.
00:21:37.240 This is a challenging forecast, but we will do our best to move forward, striving for better tools.
00:21:49.829 Play with Ruby, find the weird things, keep Ruby weird.
00:21:57.230 In conclusion, I declare that I will keep Ruby users weird.
00:22:21.480 Thank you, Matz! I enjoyed your presentation. I like the ideas around changing the hashes.
00:22:29.360 I think that all of them have very good arguments.
00:22:38.740 I believe we have some time for questions. Does anyone want to grill Matz on stuff like his production code?
00:22:45.370 Yes? You over at the opposite side of the room?
00:22:52.300 Can you talk about an interesting breaking change that you wanted to make but haven’t?
00:22:59.920 One thing I abandoned years ago was changing the scope of local variables in Ruby.
00:23:06.900 Local variable scope is limited to the block, the method, or the class in which the variable is first assigned.
00:23:15.770 In many cases, you want to use the local variable out of the block.
00:23:23.840 For example, you find an object in a loop, and you want to use that object afterward.
00:23:34.280 In that case, in current Ruby, you have to assign the local variable first. Then you have to assign it in the loop.
00:23:42.920 I tried to introduce scope hoisting, like in Java or JavaScript, so you could declare a block variable outside.
00:23:55.180 But upon further consideration, that idea became confusing.
00:24:03.320 So, I abandoned that idea. I keep a long list of these kinds of crazy ideas.
00:24:09.810 Many are abandoned.
00:24:14.780 Thank you! Making that change was too big a scope?
00:24:22.230 No, not at all! It was just a bit tricky.
00:24:27.050 Any more questions? Yes, we have some time, so preferably somebody from the corner.