Ruby
Functional programming for fun and profit!!

Summarized using AI

Functional programming for fun and profit!!

Jenny Shih • February 28, 2023 • online

The video titled "Functional programming for fun and profit!!" features Jenny Shih, a speaker at the WNB.rb Meetup, who introduces the concepts of functional programming (FP) and its relevance to Ruby developers. The main theme emphasizes that FP can enhance Ruby code quality without the necessity of mastering complex terminology such as monads and functors.

The key points discussed include:
- Understanding Programming Paradigms: Shih outlines that programming languages can be categorized into paradigms, such as object-oriented and functional programming. FP is presented as an important paradigm for Ruby developers to explore.

- Three Components of Programming: Each program can be broken down into value, behavior, and time, which helps streamline understanding FP in context with Ruby.

- Immutability: A core concept in FP is immutability, which suggests that values should not change once initialized. This approach can help prevent bugs related to unintended variable mutations. Shih advises using Ruby's freeze method and the newly introduced data structure in Ruby 3.2 to support immutability.

- Pure Functions: Shih describes pure functions that only depend on their input arguments, which do not produce side effects. It is emphasized that pure functions simplify debugging and testing. Examples demonstrate how to transform impure functions into pure ones using parameterization and returning new data structures instead of modifying existing ones.

- Handling Concurrency: The discussion transitions into the concept of concurrency in programming. By separating values and behaviors, FP facilitates easier concurrent programming. Shih compares Ruby’s limitations with the global interpreter lock against Elixir's actor model, which allows concurrent execution of functions safely without implicit state mutations. Ruby's experimental Rector is also mentioned as an emerging feature to improve concurrency.

In conclusion, the talk aims to persuade Ruby developers to adopt FP principles, emphasizing that leveraging these concepts can lead to improved code quality and maintainability. The video encourages attendees to explore FP more deeply and utilize its methodologies in Ruby projects, thus making programming both fun and profitable.

Functional programming for fun and profit!!
Jenny Shih • February 28, 2023 • online

Functional programming brings you not just fun, but also profit! Have you ever felt curious towards functional programming (FP)? Were you, soon afterwards, intimidated by the mystic terms like monads and functors? Do you think FP is not related to your Ruby work and thus, useless? Guess what-you can actually apply FP to your Ruby projects and reap benefits from it before fully understanding what a monad is!This talk will walk you through the powerful mental models and tools that FP gives us, and how we can readily use them to improve our apps in a language that we all love and understand.
https://www.wnb-rb.dev/meetups/2023/02/28

WNB.rb Meetup

00:00:00.060 I want to share a tale before I begin
00:00:03.120 I've given several talks before but I've
00:00:05.220 never looked at my own recording it's
00:00:07.140 because it's too awkward to watch myself
00:00:09.300 talk but today I clicked open one of my
00:00:12.300 recordings because of this whole other
00:00:14.460 story of about how I realized this
00:00:17.640 morning I deleted my flights for today
00:00:19.800 and I had to rework
00:00:22.199 um everything
00:00:24.119 again and then I realized that I when
00:00:28.500 while I was watching the recording I
00:00:30.779 realized that I say so many um when I'm
00:00:33.480 presenting it was a really painful to
00:00:36.480 watch
00:00:37.559 so the takeaway is that if anyone is
00:00:40.620 presenting in the future it is extremely
00:00:43.920 helpful to record and watch yourself
00:00:45.960 first if you have already
00:00:49.559 um another takeaways I'm going to say a
00:00:52.379 lot of um
00:00:53.879 um today so please bear with me
00:00:57.239 all right with that
00:00:59.399 I am my name is Jenny uh
00:01:03.739 I am I work at Shopify and I am from
00:01:08.220 Taiwan but I moved to Toronto Canada
00:01:11.240 later last year and it's been cold
00:01:16.740 um another random fact about me is that
00:01:19.080 I when I come across something
00:01:20.820 interesting I sometimes get too obsessed
00:01:23.700 and make a top cut of it
00:01:26.880 so
00:01:28.979 like functional programming
00:01:31.259 so the hypers up for the topic here is
00:01:33.840 an article from GitHub reading project
00:01:35.700 last year that talks about the rising of
00:01:38.759 functional programming over the past
00:01:40.140 decade
00:01:42.780 even though the term has become popular
00:01:45.140 there are still some common conceptions
00:01:47.640 about functional programming that might
00:01:49.380 be misleading like you have to take math
00:01:52.979 and be able to explain bonad in two
00:01:55.680 minutes
00:01:57.780 but I want to explain in Ruby developers
00:02:02.460 term what functional programming is
00:02:05.880 and even more relevant to us why should
00:02:08.640 we care about it
00:02:11.280 the main point I want to convince you
00:02:13.200 today is that functional programming
00:02:16.020 helps us write better Ruby code
00:02:20.760 and to properly understand what a
00:02:23.640 functional programming is let's first
00:02:25.140 talk about programming paradigms
00:02:27.959 it is a way to classify programming
00:02:30.239 languages based on their features
00:02:33.260 so oftentimes you hear people say Ruby
00:02:36.599 is a object-oriented language because it
00:02:39.959 a lot of its concepts are based on the
00:02:41.940 object-oriented parenting
00:02:43.980 and the functional programming that
00:02:46.560 we're talking about today is another
00:02:48.239 programming paradigm
00:02:50.760 and let's look at the mental model to
00:02:52.860 ease our way into understanding that
00:02:54.959 more
00:02:56.660 for every program we can break them down
00:02:59.640 into three components
00:03:01.680 value behavior and time
00:03:05.160 what does that mean
00:03:06.720 say today we have a program that has
00:03:09.480 this expression uh puts hello world
00:03:13.319 in this example puts is a behavior hello
00:03:17.280 world is the value
00:03:19.580 another example we assigned wmbrv to the
00:03:23.760 variable Faith group
00:03:25.920 called up case on it
00:03:29.879 does the value of a variable is now
00:03:32.280 different in different
00:03:33.980 execution point so we see the time
00:03:37.140 element in between those two expressions
00:03:41.819 to look at our mental model again and
00:03:44.580 try to use the three components to an
00:03:46.620 object-oriented program
00:03:48.420 it will look something like this
00:03:51.239 the time element is within both value
00:03:53.879 and behavior because taking both about
00:03:57.000 both both those two components can
00:03:59.459 change over time and they are all
00:04:02.280 encapsulated into object
00:04:05.040 and we'll have more options so while
00:04:09.000 while each having the same arrangement
00:04:10.920 of those components
00:04:14.879 if we model functional programming with
00:04:17.280 the same three components we have three
00:04:19.979 distinct circles
00:04:22.440 so now let's look at them one by one
00:04:24.840 first of all value
00:04:27.919 to talk about value in functional
00:04:30.540 programming we need to talk about the
00:04:32.220 concept of immutability
00:04:35.340 and the not overly complicated
00:04:37.919 definition of it is don't change a value
00:04:41.340 once you initialize it
00:04:43.740 in Ruby it would be like adding the
00:04:46.320 method freeze on objects like like this
00:04:49.800 example
00:04:52.919 and also in class definition
00:04:55.520 we will discard the attribute writer and
00:04:59.040 attribute ancestor on the instance
00:05:00.840 variables
00:05:01.919 because having them means we're giving
00:05:04.620 open assets to modify the values of the
00:05:07.139 instance variables and we don't want
00:05:08.940 that
00:05:11.940 and why we want immutability
00:05:15.680 from a developer's point of view it is a
00:05:18.960 lot easier to reason about the code if
00:05:21.060 you know that there's a guarantee that
00:05:23.699 the values cannot be changed
00:05:27.419 as an example we Define a struct called
00:05:30.300 flight with an attribute date
00:05:33.180 and I need initialize my flight variable
00:05:36.360 with a certain date and then I share
00:05:39.240 this value with another variable called
00:05:41.639 friends fights
00:05:43.139 later the Flint the French flight
00:05:45.539 changed its state to a day earlier
00:05:48.240 and now when I expect my fight I will
00:05:51.720 see that the date of my fight has also
00:05:54.780 been changed
00:05:57.720 that example was already short one so
00:06:00.360 it's easier to spot the mistake but
00:06:03.240 normally we'll be working with a much
00:06:05.220 larger code base where a variable can be
00:06:07.500 can easily change values across
00:06:10.199 different files
00:06:11.600 and
00:06:13.199 um and it will be painful if if a bug
00:06:15.419 happens in one of those intermediate
00:06:17.820 value states of the variable
00:06:21.780 and the second reason is uh
00:06:25.560 is from the wrong times point of view
00:06:28.440 without the need to worry about a value
00:06:32.360 and if it will be changed later or not
00:06:35.039 it can be a lot easier to support
00:06:37.620 concurrency which I will talk about more
00:06:40.620 in details later
00:06:44.759 okay so next question will be how
00:06:48.960 first uh the new data structure called
00:06:51.300 Data is just released in Ruby 3.2
00:06:55.620 this is the piala introduced it
00:06:58.620 it aims to be a simple imputable value
00:07:01.979 object
00:07:03.060 so instead of using class or shot to
00:07:06.180 Define our object we can now use the
00:07:08.880 data class and a guarantee of
00:07:10.919 immutability will just come out of the
00:07:12.960 box when you use it
00:07:15.740 if you are not Ruby 3.2 yet but still
00:07:20.340 want to try out this idea there's a gem
00:07:23.580 called joist shot that does the same
00:07:25.979 thing for you
00:07:28.080 it is dry shock is part of the dry ruby
00:07:31.860 collection you can visit dry ruby.org to
00:07:34.560 find out more
00:07:35.639 there's
00:07:37.139 um a lot of functional programming ideas
00:07:38.900 in the in the collection not just this
00:07:41.340 one so definitely check it out if you
00:07:43.500 want to dig more into functional
00:07:44.699 programming and how it's realized with
00:07:46.919 Ruby
00:07:48.800 so that concludes the value part of the
00:07:51.660 functional programming paradigm
00:07:53.699 the core idea of it is immutable data
00:07:58.080 next we look at Behavior
00:08:00.740 the key idea here is pure functions
00:08:05.699 a pure function is defined in two
00:08:07.680 conditions first it only depends on its
00:08:10.860 input argument
00:08:12.380 for example this function is not pure
00:08:15.720 because there's there's no input
00:08:17.880 argument but it relies on the time
00:08:20.099 module to produce the value so you'll be
00:08:23.520 you'll be different every time you call
00:08:25.319 it
00:08:26.940 and if we change it a bit and instead of
00:08:30.419 calling a Time module right inside the
00:08:33.180 definition we can pass the timestamp
00:08:36.360 step instead from argument
00:08:39.240 then it's a preview function because as
00:08:41.520 long as argument is the same the result
00:08:43.800 will be the same
00:08:46.080 the second condition is that it does not
00:08:48.300 mutate states that is it has no side
00:08:51.360 effects
00:08:53.160 so this is not a pure function
00:08:55.740 although it satisfy the first condition
00:08:57.920 it has changed the variable stir Forever
00:09:01.920 by appending to exclamation marks to it
00:09:06.779 if we change it to this then it's a pure
00:09:10.019 function
00:09:11.339 because it doesn't modify the stir
00:09:13.500 itself
00:09:15.839 as to why I will read this quote
00:09:19.080 the problem with all languages is
00:09:21.540 they've got all this implicit
00:09:23.160 environment that they carry around with
00:09:24.839 them
00:09:25.560 you want a banana but what you got was a
00:09:28.440 gorilla holding the banana in the entire
00:09:30.839 jungle
00:09:32.459 and this is this code is by Joe
00:09:34.200 Armstrong creator of erlang a functional
00:09:38.220 link a programming language
00:09:41.279 I will highlight the word implicit
00:09:43.260 environment here
00:09:46.080 I think the analogy captures the essence
00:09:49.320 of why pure function is a good thing so
00:09:52.019 here is an effort of illustration
00:09:56.580 suppose the the orange circle is our
00:09:59.760 brain
00:10:00.600 and if we don't have pure functions that
00:10:04.500 means when we look at a function in this
00:10:06.420 case the banana we can't just focus on
00:10:08.880 that but also need to pay attention to a
00:10:11.279 lot of other parts external to this
00:10:14.100 function because if we don't do that we
00:10:16.320 may find ourselves missing certain key
00:10:18.180 aspects of the function or would be
00:10:20.580 modifying some states somewhere else
00:10:22.140 that would have some effects down the
00:10:24.420 road
00:10:25.760 and that would be that can be
00:10:28.680 overwhelming
00:10:30.540 on the other hand if we are able to
00:10:32.640 focus on the function as it is
00:10:36.060 with would be I will have more brain
00:10:38.640 space focus on the details of the
00:10:41.160 function itself
00:10:43.019 and that's more likely to reduce bugs
00:10:47.480 it will also give us a much easier time
00:10:50.160 to write the tests because pure
00:10:52.019 functions are by definition isolated
00:10:57.360 and you also give the reverse the pr
00:11:00.180 reviewers an easier time because now
00:11:02.279 your PR is so small and neat so it's
00:11:05.519 basically a wing wing wing wing
00:11:08.160 situation
00:11:11.160 with that how do we do that
00:11:13.980 the first technique that we can use to
00:11:16.260 produce pure function is
00:11:18.620 parameterization in functional
00:11:20.700 programming's term or
00:11:22.440 dependency injections in object-oriented
00:11:25.620 term
00:11:27.260 this is an example
00:11:29.459 this is a new standard class and we have
00:11:32.399 a subscribe function
00:11:35.399 first inside a function we first check
00:11:37.860 some conditions
00:11:39.240 return false if those conditions are not
00:11:41.820 met
00:11:43.079 and if they do pass you add the email to
00:11:46.140 the mailing list and return to
00:11:50.100 there are some traits that make it not
00:11:53.279 pure
00:11:54.779 first we are calling an outside module
00:11:57.360 to dual validation first
00:12:00.600 and we're also relying on the instance
00:12:02.579 variable mailing list and that is a
00:12:05.640 state that we have no control of
00:12:09.000 to fix it we can move the two things to
00:12:12.180 the parameter list
00:12:14.339 now we don't rely on implicit knowledge
00:12:16.380 of the outside world for this function
00:12:20.279 but there's still a thing that makes it
00:12:23.100 not pure
00:12:24.120 in this in this operation is modifying
00:12:27.660 the state of mailing list
00:12:30.240 and that brings the second technique
00:12:32.820 transformation instead of mutation
00:12:35.940 instead of relying on
00:12:38.600 relying implicitly modifying the mailing
00:12:41.700 list
00:12:42.540 we can just return the new array as a
00:12:44.880 return value and preserve the original
00:12:46.620 value
00:12:48.420 like this
00:12:50.820 now if we pass this new set newsletter
00:12:53.459 class to the two conditions
00:12:55.560 only depends on its agreement check
00:12:59.339 does not mutate States check
00:13:02.459 so that's the behavior part of
00:13:05.040 functional programming
00:13:06.540 the key idea is pure function
00:13:09.899 the last component is time
00:13:12.000 and this is where we talk about
00:13:13.560 concurrency
00:13:16.200 as we've seen before this is how I think
00:13:19.079 about an oo program in my head
00:13:22.860 and if we try to run a ruby Chrome brand
00:13:25.800 concurrently out of the box we cannot
00:13:29.339 there's is this thing called the global
00:13:31.920 interpreter lock that prevents Ruby
00:13:34.740 color from doing so
00:13:36.240 and the reason that we needed this log
00:13:38.339 in the first place is clear safety that
00:13:41.639 is uh there's a risk in messing up the
00:13:44.040 timeline of object mutations thus
00:13:45.959 messing up the program itself
00:13:49.019 the functional programming is quite good
00:13:50.820 at handling this because it separates
00:13:52.940 the time element out of the value and
00:13:57.480 behavior
00:13:59.459 which makes concurrency easy
00:14:02.959 take Elixir uh another functional
00:14:05.880 programming language take elixirs
00:14:08.700 currency model as example
00:14:12.360 um it uses the this actor model so here
00:14:17.339 we Define a process or an actor as a
00:14:20.040 unit of execution they can run
00:14:22.860 concurrently and they they will try to
00:14:24.959 communicate with Azure they can only
00:14:27.300 communicate with each other by sending
00:14:29.399 messages instead of mutating the States
00:14:31.680 of each other
00:14:33.959 and this is what it looks like when
00:14:36.060 running with multiple threads
00:14:38.820 um
00:14:39.860 and one reason that Elixir is uh is is
00:14:43.920 great at this and can easily achieve
00:14:46.620 this state is that it doesn't need to
00:14:49.139 worry about the state's problem and it
00:14:51.000 doesn't need so so it doesn't need a lot
00:14:53.279 like like Ruby does
00:14:56.480 in recent years Ruby has also started to
00:15:00.000 build its own concurrency Obsession it's
00:15:01.800 called Rector
00:15:03.000 Matsu South said so that it's very
00:15:05.639 important
00:15:07.760 this is how we can understand Rector
00:15:10.339 erector is also a unit of of execution
00:15:14.880 but what's different with the Elixir
00:15:17.880 model is that each direct each Vector
00:15:20.820 contains multiple threads whereas a
00:15:23.100 thread in
00:15:24.320 with Elixir it can cannot contain
00:15:28.279 millions of Elixir actors
00:15:32.699 and each factor can has a clear boundary
00:15:37.579 and and is only interpreter lock instead
00:15:40.920 of just one Global lock so now the right
00:15:44.699 the directors can run concurrently of
00:15:47.220 each other while still guarantee that
00:15:49.740 the code inside each Vector is run
00:15:52.260 sequentially
00:15:55.680 and as of Ruby 3.2 Rector is still
00:15:59.940 flagged as experimental but
00:16:03.300 um it's very exciting to to see
00:16:05.880 development in the future
00:16:08.600 okay and that concludes the three
00:16:12.300 components of the functional programming
00:16:14.880 um
00:16:15.720 to recap a functional programming has
00:16:18.600 three uh in three components
00:16:22.440 we looked at the value and the
00:16:24.959 importance of immutable data
00:16:27.420 and we looked at the behavior and the
00:16:29.760 importance of fear function
00:16:32.160 and how with the separation of time we
00:16:34.740 can achieve concurrency
00:16:37.440 but that's I hope I've
00:16:40.759 convinced you that we that by borrowing
00:16:44.339 those ideas from functional programming
00:16:46.019 and cooperating into a rubiko we can
00:16:48.600 make
00:16:49.380 we can write better and more methane
00:16:52.800 thank you
00:16:54.360 the rest will be resources feel free to
00:16:57.660 check it out if you're interested
Explore all talks recorded at WNB.rb Meetup
+20