Introduction to Elixir - Streams, Hierarchical Data, Updating Immutable Data - Part Seven

Tensor Programming · Beginner ·🛠️ AI Tools & Apps ·7y ago

Key Takeaways

Covers data abstraction in Elixir, including Structs and the pipe operator

Full Transcript

hey guys welcome back to the introduction to elixir part 7 my name is tensor and today we're going to continue looking at data abstraction in elixir so first let me just touch on data visibility in elixir it's important to note that data is always transparent this means that a client can always read any information from your Struck's and any other data type that you create and that there's not an easy way of preventing that in other words encapsulation works rather differently than in a typical object-oriented language in elixir modules are in charge of extracting the data and providing operations to manipulate and query that data but the data itself is never hidden so with that out of the way let's go ahead and extend our task list abstraction to provide basic crud support now we already have the create and read parts of our module sorted with the add task and the get tasks functions respectively but we want to add support for updating and deleting entries inside of our task list map to do this we need to have some way to uniquely identify each of the entries that exists inside of our task list we want to essentially refactor the task list into a structure and then give each of our entries a specific ID so what I'm going to do is actually come in here and delete this multi-storage module and then at the top of the task list let's go ahead and define a struct and this struct will contain two keys a key for the ID and then a key for the entries which is just a map so ID by default will start at 0 and we'll make it so that this ID increments as we add entries to our task list and then the entries of course will sit inside of the map so essentially we're creating a nested data structure that's going to look something like this so we have the task list and the task list has its entries map and the entries map as the key which will be the ID of the entry followed by a map which will contain a date ID and a title and then the ant task list will also have the ID field which will be incremented based on how many entries are in here so since we have one entry in here the ID is now 1 and then if we had say entry 1 in here then the ID would increment up to 2 and so on and so forth now before we actually implement our update function we need to of course refactor our current functions and move them away from using the multi-store it's a module that doesn't exist anymore and so for our new function all we really need to do is create a new instance of our task list struct for the add task function we need to follow three different steps we first need to set the ID of the entry that's being added then we need to add a new entry to the collection and then finally we need to increment the ID field so first let's set the ID for the entry that's being added and we can do this by taking the entry and then redefining it calling map dot put we pass in the map that we want to modify which is the entry itself and we pass in the key that we want to modify which is the ID Adam and then we can take the task lists ID field and put it into our entry now that we have the ID inside of the entry that we want to add we need to modify and put that entry into our task list entries map and so we can go ahead and create a new entries map by calling mapped output on task list dot entries we're going to be assigning this entry to task list ID and then we pass in the value which is just our entry variable that we created up here and finally after we've created this entry and then the new entries map we can go ahead and output a new task list struct by using the cons op Reiter and the task list that's being passed into the function so we say task list task list cons are changing the entries map to be our new entries map which we created up here and then we want to auto increment the ID so we can just call task list dot ID plus one so if we pass in say a task list and the current ID of that task list is one then it will increment to two and then the output will have ID of two and then if we pass that in then it would increment to three and so on now it's important to keep in mind that this function is working on this heavily nested structure that we've created here so because we've got the struct on the outside then we've got this inner map followed by an even further inner map we need to use the map put function in this way so that we can then modify the task list and then return a new immutable task list and this is something that you'll find that you're doing quite often when you're working with immutable data structures now we can go ahead and implement our get tasks function and this is actually fairly simple and it's going to be very similar to what we had before so before remember we took in the task list and then the date that we wanted to find and then we output it a list of the entries that contain that given date well take the entries map that's inside of the task list that we're passing in to this function and we'll pipe it into a function called stream dot filter now stream type filter is very similar to enum dot filter or mapped out filter in that it takes in a predicate function that is a function that outputs a boolean and then any of the elements that output a boolean of true get kept inside of the enumerator so in other words we're looking for any of the entries where the entry dot date is equal to the date that we're passing into this function and if the entry date is equal to that date then that entry is kept inside of our enumerator or our stream in this case now let's talk about streams for a moment so that you can fully understand why we're using this stream dot filter function streams are a special kind of enumerable they can be useful for doing lazy composable operations over anything that is enumerable if you look at the stream module itself you'll see that a lot of the functions inside of it are actually very similar to the EMU module the main advantage of using a stream is the fact that it is lazy which means that it produces the actual result on demand so in other words the stream doesn't actually produce any data until it is needed so if we create a stream like this say I put in our list of 1 through 5 and then I call stream dot map and I'm taking each of these values and just multiplying it by itself you'll see here that we do not actually get back on a numerable where we have the result of calling this function on every element of this list instead we get back this stream data type which has in the e neumann side of it and then the function that we're calling on this enum inside of it as well and this is essentially just a symbolic data type that stands in the place of the actual computation we can actually resolve the computation by taking the stream and passing it into say enum 2 list which will give us back a list of all of these items multiplied by one another so we get 1 4 9 16 and 25 now the main use of streams is for when you're doing computations that may not send back data when you expect it to come back computations for instance like reading from a file or reading from a web api do not always send back data at a given moment when it needs to be computed and so streams are essentially just asynchronous enumerables this is why we're actually using the inu map function to take this stream object that we're getting back from stream dot filter and then convert it into a list which we can then send back to the user so now we've gone in and re-implemented our create function and our to read functions let's go ahead and create our update function with our update function we need to ask how our update function is going to be used and there are really two possible options in this particular implementation we could create a function that will accept an ID for a value for an entry and then an update or lambda function and then this will work in a way that's similar to map update in that the lambda will receive the original entry and then it will return the modified version of that entry the other way that we could implement this is by creating a function that will accept the entry map and then if an entry with the same ID exists in the entries map it will then be replaced by our new entry for this implementation I'm going to go with the first implementation so we're going to pass in the ID value for the entry that we want to change and then an update or lambda so our update function will be called update task it will take in the task list it will then take in the entry ID and then it will take in our update function now remember we're just updating the entries map inside of our task list by changing a piece of data that's already in there so we can use map dot fetch to go ahead and fetch the entry ID inside of our task list dot entries map and of course because we want to deal with a potential case where we do not actually get back the entry that we're looking for we can use the case construct so if we get back an error atom from calling map fetch and we just want to return the original task list which is being passed into the update task function if however we get back a tuple of okay followed by some value which will be the old entry that we fetched from the map we can go ahead and use that old entry to create our new entry by calling our updater function on that old entry and then we can create a new trees map by calling map put on our task list entries map we want to of course put this value into the new entry ID and the value will be the new entry itself and then we need to pass back a task list struck where we've changed the entries field with our new entries map so again we can use the Khans operator with our original task list and then just change the entries field by putting in our new entries variable the function will work quite fine but because we never really specified the type of data that the updater function can return we could potentially corrupt our entire structure because the user could pass in a lambda that doesn't return the appropriate data type to fix this we can go ahead and use pattern matching and we can create another function called update task this time of era d2 this will allow us to verify that the new entry that we're passing in is indeed a map so we can go ahead and take in the task list then check to see that new entry is a map and then we can use this data to call to our update tasks of era d3 function with the task list the new entry ID and then a function which will be our updater function we have the old entry which would be the argument here and since we don't really care about the old entry we can just put an underscore and then we just want to return the new entry and so this would actually update the value inside of our structure so now let's go ahead and actually use our new task list module so I'm gonna create a variable called task list I'm gonna call task list new first then pipe that into task list add tasks and I'll put a map in here with date title and then I'll pipe that into another task list add tasks and again this will be a map with date and title and then finally we'll have our third task which will be added with another add tasks Carl and you can see here that we get back a task list where we have our entries filled and then the ID field we can go ahead and take this task list variable and update one of the fields inside of it specifically I'm going to update the field ID of 0 which is this field here so I'm just going to type task list into task list I'll update tasks and then pass in a new date and a new title and then passing the ID of the entry that I want to update and you can see here that we do indeed get back a new task list struct and for ID 0 we have a new date and a new title inside of this update task function we just performed a pretty deep update of an immutable hierarchy so this is the size of our task list structure and we've updated one entry inside of multiple structures when you work with immutable data structures like this specifically highly nested immutable data like this you can't directly modify a part of it especially if that part resides deeply in the tree instead you actually have to walk down the tree to the particular part that needs to be modified and then transform it as well as all of its ancestors the result is a copy of the entire model in this case our task list now of course our two versions of the task list will share memory now imagine we have a list of entries like this and we want to be able to add all of these entries to a new task list object to facilitate this we can go ahead and modify our new function and make it so that we can pass in a optional parameter that will iteratively build our to-do list with these entries so we can change this new function into a function that takes in one argument and that argument will be an optional argument if we pass it in we'll bind it to the entries variable otherwise it'll just be an empty list inside of this new function we can simply call a new Murray deuce we pass in our entries and what we want to do is reduce our entries into a single task list instance so iam reduce takes in the correction that you want to modify or the enumeration and then you put in the first value of the accumulator which in this case is just an empty task list and then we have a function and this function will then essentially create our task list by adding each entry into it iteratively so we go through we take an entry from our entries list and then we take the accumulator which starts out as task list and then we call add task with our task list here and then the entry then so this uses this to update the task list data structure and then we would do that over and over again for each of the entries inside of our list let's go ahead and put these entries into our IEX terminal and then we can go ahead and pipe our entries into our task list new function like this and as you can see it creates a new instance of the task list with these three entries inside of it alright guys well I hope you enjoyed this tutorial if you did feel free to like and subscribe if you have any questions or comments feel free to leave them in the box below and if you want to continue to get updates on this particular series or any of my other series go ahead and click that notification bell if you dislike this video then by all means download it as much as you like have a good night

Original Description

#tensorprogramming #elixir #introtoelixir In this tutorial, we take a look at how to abstract data in Elixir. We look at Structs and we also look at the pipe operator. Source Code: https://github.com/tensor-programming/intro-to-elixir/tree/tensor-programming-part-7 Request Form: https://goo.gl/forms/rFjHcZMRJ3bYPEC03 Cloudways Web App Hosting: https://www.cloudways.com/en/?id=507366 Feel free to support the channel: Patreon: https://www.patreon.com/tensor_programming Check out our Twitter: https://twitter.com/TensorProgram Check out our Facebook: https://www.facebook.com/Tensor-Programming-1197847143611799/
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from Tensor Programming · Tensor Programming · 0 of 60

← Previous Next →
1 NodeJs, Text editors and IDEs
NodeJs, Text editors and IDEs
Tensor Programming
2 Vanilla JS todo App
Vanilla JS todo App
Tensor Programming
3 Elm Tutorial part 1
Elm Tutorial part 1
Tensor Programming
4 Elm Lang Tutorial, Part 2
Elm Lang Tutorial, Part 2
Tensor Programming
5 Elm Tutorial Part 3
Elm Tutorial Part 3
Tensor Programming
6 Elm Tutorial Part 4 -- Analog Clock App
Elm Tutorial Part 4 -- Analog Clock App
Tensor Programming
7 Elm Tutorial part 5 -- Snake Game
Elm Tutorial part 5 -- Snake Game
Tensor Programming
8 Elm Tutorial part 6 -- Calculator
Elm Tutorial part 6 -- Calculator
Tensor Programming
9 Go Tutorial part 1 -- Hello World and Static File Server
Go Tutorial part 1 -- Hello World and Static File Server
Tensor Programming
10 Go Tutorial part 2 -- Web Crawler
Go Tutorial part 2 -- Web Crawler
Tensor Programming
11 Go Tutorial Part 3 (Web App part 1)
Go Tutorial Part 3 (Web App part 1)
Tensor Programming
12 Go tutorial Part 4 (Web tutorial part 2) - Using templates
Go tutorial Part 4 (Web tutorial part 2) - Using templates
Tensor Programming
13 Go tutorial part 5 (web app part 3)
Go tutorial part 5 (web app part 3)
Tensor Programming
14 Go tutorial part 6 (webapp part 4)
Go tutorial part 6 (webapp part 4)
Tensor Programming
15 Go tutorial part 7 (web app part 5)
Go tutorial part 7 (web app part 5)
Tensor Programming
16 Go tutorial part 8 (Web app part 6)
Go tutorial part 8 (Web app part 6)
Tensor Programming
17 Go tutorial Part 9 (web tutorial part 7)
Go tutorial Part 9 (web tutorial part 7)
Tensor Programming
18 Go tutorial Part 10 (web app part 8)
Go tutorial Part 10 (web app part 8)
Tensor Programming
19 Go tutorial Part 11 (Web app Part 9)
Go tutorial Part 11 (Web app Part 9)
Tensor Programming
20 Go Tutorial Part 12 (Web app Part 10)
Go Tutorial Part 12 (Web app Part 10)
Tensor Programming
21 Go Tutorial Part 13 (Web app Part 11)
Go Tutorial Part 13 (Web app Part 11)
Tensor Programming
22 Looking at Elm 0.18
Looking at Elm 0.18
Tensor Programming
23 Go tutorial Part 14 (Web tutorial part 12)
Go tutorial Part 14 (Web tutorial part 12)
Tensor Programming
24 Go tutorial Part 15 (Web tutorial part 13)
Go tutorial Part 15 (Web tutorial part 13)
Tensor Programming
25 Go tutorial part 16 (web app part 14)
Go tutorial part 16 (web app part 14)
Tensor Programming
26 Elm Tutorial Part 7 (SPA part 1)
Elm Tutorial Part 7 (SPA part 1)
Tensor Programming
27 Elm Tutorial Part 8 (SPA Part 2)
Elm Tutorial Part 8 (SPA Part 2)
Tensor Programming
28 Electron Elm Tutorial
Electron Elm Tutorial
Tensor Programming
29 Go tutorial part 17 (web app part 15)
Go tutorial part 17 (web app part 15)
Tensor Programming
30 Up and Coming Programming Languages and Technologies for 2017
Up and Coming Programming Languages and Technologies for 2017
Tensor Programming
31 elixir tutorial part 1
elixir tutorial part 1
Tensor Programming
32 elixir tutorial part 2
elixir tutorial part 2
Tensor Programming
33 Elixir tutorial Part 3 (GenServer and Supervisor)
Elixir tutorial Part 3 (GenServer and Supervisor)
Tensor Programming
34 Elixir Tutorial Part 4 (GenStage)
Elixir Tutorial Part 4 (GenStage)
Tensor Programming
35 Elixir Tutorial Part 5 (Plug and Cowboy)
Elixir Tutorial Part 5 (Plug and Cowboy)
Tensor Programming
36 Phoenix Framework Tutorial Part 1 (elixir part 6)
Phoenix Framework Tutorial Part 1 (elixir part 6)
Tensor Programming
37 Phoenix Framework Tutorial Part 2  (elixir part 7)
Phoenix Framework Tutorial Part 2 (elixir part 7)
Tensor Programming
38 Phoenix Framework Tutorial Part 3 (elixir part 8)
Phoenix Framework Tutorial Part 3 (elixir part 8)
Tensor Programming
39 A Intro to Clojure and Clojure Syntax
A Intro to Clojure and Clojure Syntax
Tensor Programming
40 An Update about the channel
An Update about the channel
Tensor Programming
41 Intro to Rustlang (Setup and Primitives)
Intro to Rustlang (Setup and Primitives)
Tensor Programming
42 Intro to Rustlang (Strings, Tuples, Arrays, Slices and Pretty Printing)
Intro to Rustlang (Strings, Tuples, Arrays, Slices and Pretty Printing)
Tensor Programming
43 Intro to Rustlang (Ownership and Borrowing)
Intro to Rustlang (Ownership and Borrowing)
Tensor Programming
44 Intro to Rustlang (Structs, Methods, Functions, Related Functions and the Display/Debug Traits)
Intro to Rustlang (Structs, Methods, Functions, Related Functions and the Display/Debug Traits)
Tensor Programming
45 Intro to Rustlang (Control Flow, Conditionals and Pattern Matching)
Intro to Rustlang (Control Flow, Conditionals and Pattern Matching)
Tensor Programming
46 Intro to RustLang (Enums and Options)
Intro to RustLang (Enums and Options)
Tensor Programming
47 Intro to Rustlang (Vectors, HashMaps, Casting, If-Let, While-Let, and the Result Enum)
Intro to Rustlang (Vectors, HashMaps, Casting, If-Let, While-Let, and the Result Enum)
Tensor Programming
48 Rustlang Project: Snake Game
Rustlang Project: Snake Game
Tensor Programming
49 Intro to Rustlang (Traits and Generic Types)
Intro to Rustlang (Traits and Generic Types)
Tensor Programming
50 Intro to Rust-lang (Closures, the Box Pointer and Iterators)
Intro to Rust-lang (Closures, the Box Pointer and Iterators)
Tensor Programming
51 Intro to Rust-lang (Modules and Lifetimes)
Intro to Rust-lang (Modules and Lifetimes)
Tensor Programming
52 Intro to Rust-lang (Macros and Metaprogramming)
Intro to Rust-lang (Macros and Metaprogramming)
Tensor Programming
53 Intro to Rust-lang (Error Handling)
Intro to Rust-lang (Error Handling)
Tensor Programming
54 Intro to Rust-lang (Concurrency, Threads, Channels, Mutex and Arc)
Intro to Rust-lang (Concurrency, Threads, Channels, Mutex and Arc)
Tensor Programming
55 Intro to Rust-lang (Tests, Attributes, Configuration and Conditional compilation)
Intro to Rust-lang (Tests, Attributes, Configuration and Conditional compilation)
Tensor Programming
56 Rustlang Project: Port Sniffer CLI
Rustlang Project: Port Sniffer CLI
Tensor Programming
57 Rustlang Project: Chat Application
Rustlang Project: Chat Application
Tensor Programming
58 Rustlang Project: CLI Toy Blockchain
Rustlang Project: CLI Toy Blockchain
Tensor Programming
59 Intro to Rust-lang (Setting up a Development Environment)
Intro to Rust-lang (Setting up a Development Environment)
Tensor Programming
60 Intro to Rust-lang (Building a Web API with Iron)
Intro to Rust-lang (Building a Web API with Iron)
Tensor Programming

Related Reads

Up next
6 NEW Bolt.new Updates You Probably Missed
Conor Martin
Watch →