🎙 Develpreneur Podcast Episode

Audio + transcript

Building Better Developers, Episode 481: Constructors and Initializers

In this episode, we discuss the importance of constructors and initializers in object-oriented programming. We explore the trade-off between convenience and performance, and consider the context in which a class will be used.

2021-03-30 •Season 14 • Episode 481 •Constructors and Initializers in Object-Oriented Programming •Podcast

Summary

In this episode, we discuss the importance of constructors and initializers in object-oriented programming. We explore the trade-off between convenience and performance, and consider the context in which a class will be used.

Detailed Notes

Constructors and initializers are two related concepts in object-oriented programming that serve different purposes. Constructors are used to create instances of a class, while initializers are used to populate the properties of an instance. Having a clear understanding of these concepts is crucial for effective object-oriented programming, as it allows developers to write more efficient and maintainable code. In this episode, we explore the trade-off between convenience and performance, and consider the context in which a class will be used.

Highlights

  • The difference between constructors and initializers
  • The importance of having a no-argument constructor
  • The use of initializers to populate instance properties
  • The trade-off between convenience and performance
  • The importance of considering the context in which a class will be used

Key Takeaways

  • Constructors and initializers are used for different purposes in object-oriented programming.
  • Having a no-argument constructor is essential for many classes.
  • Initializers can be used to populate instance properties, but should be used judiciously to avoid performance issues.
  • Consider the context in which a class will be used when designing constructors and initializers.
  • The trade-off between convenience and performance is a key consideration when designing constructors and initializers.

Practical Lessons

  • Use constructors and initializers to create and populate instances of a class.
  • Consider the trade-off between convenience and performance when designing constructors and initializers.
  • Use no-argument constructors and initializers to create instances of a class.

Strong Lines

  • A good example of a class is an address class with constructors that take different parameters.
  • A phone number class with constructors that take different parameters is a common use case.
  • Consider the context in which a class will be used when designing constructors and initializers.

Blog Post Angles

  • The importance of constructors and initializers in object-oriented programming.
  • The trade-off between convenience and performance in constructors and initializers.
  • The use of constructors and initializers to create and populate instances of a class.
  • The importance of considering the context in which a class will be used when designing constructors and initializers.
  • The use of no-argument constructors and initializers to create instances of a class.

Keywords

  • Constructors
  • Initializers
  • Object-Oriented Programming
  • Programming
  • Software Development
Transcript Text
This is Building Better Developers, the Develop-a-Noor podcast. We will accomplish our goals through sharing experience, improving tech skills, increasing business knowledge, and embracing life. Let's dive into the next episode. Well, hello and welcome back. We're continuing our season where we're talking about object-oriented programming. This episode, we are going to look at constructors. As part of that, we'll call them initializers. These are two things that every class, almost every class is going to have. Every class needs a constructor because what that does is says, okay, I'm going to create an instance. Now, there are different ways to do this. We sort of referenced in the prior episode, we talked about singletons and the idea of the class providing an instance of the class. There are also, we've mentioned before, the idea of factories where you send some information in and an instance of a class is produced as the result of that call. I want to just step into this a little bit and talk about really how to approach these, some thoughts on it. What we have is there's, I guess there's two extremes. The one extreme is that, well, let me step back for a second. Let's just talk general constructor. Generally with a constructor is you say, give me an instance. Now, with that, you can do a constructor that has zero parameters. It's basically give me a blank instance, an empty instance. The thought being then I'm going to go ahead and populate those values. I'm going to start working with that instance. Again, this is assuming that it has instance level attributes, which most classes are going to. On the other hand, another way you could do it is you could have a constructor that has got parameters to fill all the properties so that when I create a constructor, I actually send it a bunch of values and say, here's a bunch of values. Give me back an instance of this class. Those are the two extremes I started to reference. In between there, you may have something where you, maybe, and you can have multiple constructors. They're going to be differentiated by the parameters you send. It could be that I have a blank constructor that says, I just want an empty class. It could be that I have a constructor that I provide all the properties. It may be that I have one where I essentially give it another instance and my constructor basically says, create an instance that looks like this instance that I'm sending you. Also, you can have constructors where you give a few of the values and say, well, here's a couple of, we'll call them required values that I'm going to set. You give me an instance back and I will populate the other values as needed. Sometimes those can be challenges as far as what do I want to build for my class? How do I build it so that I make it easy to use but also handle the proper object-oriented concepts and things like that? Now, generally speaking, the safe approach is to just have a blank, essentially an empty instance kind of thing. I do a constructor, I get an instance back, and then I leave it up to the developer to populate all those values. The challenge is that that often is time-consuming and tedious. In a lot of cases, it's a lot easier to send a couple of variable parameters in and then have those things populate out the instance properties as needed. Sometimes that includes some side effects and things like that. There may be some calculated instance variables that you need to set up. Don't just give me, as a class, I'm saying don't just say, give me an instance. Give me some context so I can give you an instance that at least gets you off to a good start. The alternative, depending on how you've set it up, may be that you have a constructor and then you immediately follow it by instance.setA, setB, setC, setting all of those properties. This is where initializers can come into play. I can, instead of sending those properties in or individually setting all of them, I may have an initializer that says, I'm going to get an instance. I do have maybe a need to provide just a blank instance. If somebody is using it in the common form of it, then I'm going to send an initializer. I'm going to create an initializer, which is a different method, which says I'm going to give you some information and you're going to use that information to populate out that instance so that it has properties that are contextually what I need. A real common use of this would be if you have something that's got a backing data store of some sort, is that you could create an instance and then you have something like, I would say call it a load function. Load would essentially be the initializer. You would say, give me an instance and then I'm going to do instance.load and I'm going to send it an ID value. It's going to use that ID to go look up a bunch of stuff and basically pull it back out of the serialized approach where it was, wherever it was stored. I store it off. I grab an instance. I tell the instance, here's an ID. Why don't you go load the values for it? And boom, it's off and running. You'll also see this with commonly used values. An example would be an address. Maybe with an address, I've got an address class and I get an instance and I initialize it and maybe I'll just initialize it. The initialize is street, city, state, zip. has values for country, street, essentially address line two and maybe a couple other things that are there. I can basically lead the developer to say, these are required or common fields and here is an easy way to set those without making all of those individual calls. That's, of course, it is going to be faster. It's going to be quicker to do the one call. Send it a bunch of values, do all of the setup internally within that instance, and then move forward with it as opposed to having to do all the individual sets. Plus, it implies what those required fields are because you're going to say, you need to give me these five values for me to properly initialize this class. You can even have stuff, and you'll see this, for example, with maybe file manipulation stuff or things like that where you get a file instance, but if you haven't provided it a file name, then there's a whole bunch of stuff that won't work. You have some sort of a validation that says, hey, this is not a valid instance. You can actually check that fairly quickly. With your initialize, that says, if you give me this, I'm going to give you back a valid instance or I'm going to set your instance up to be valid. Otherwise, you're playing with something that's not in a workable state, essentially. This is where balance essentially comes into it and utilizing the opportunity to have multiple constructors. There are definitely situations where a blank constructor is needed, where you need to have the ability to create an instance from scratch, as we call it, as we may refer to it. There are also going to be instances where you say, you know what, or situations where you say, I just want to send a bunch of this data in and have the instance be properly built. In particular, you may find this in things like, as I said, if you're pulling it out of a file or maybe that you've got some complicated line of data, maybe it's like a fixed length, you've got this string of data or something like that, that you need it to, part of the instance, you need it to parse that and put all the things in the right place. There's a lot of things like that that would make it where it makes sense to have a, we'll call it a complicated constructor that takes a parameter or multiple parameters and maybe does a lot of work to get that instance to a certain state. Of course, there's still going to be those situations where you have one that you want a blank, want an empty, a blank instance to work with. With that being said, I know as a programmer, I've gotten really frustrated in situations where I can't get a blank instance, where instead I have a whole lot of, I have other work I have to do to get to using an instance of some sort. That means that ideally you should always have a constructor that's a no parameter constructor, I think. You should always do that unless there is a requirement in some way that means that that should never happen, in which case, okay, you can get rid of the blank constructor. An example would be in a Singleton, you don't want to have actually a constructor at all. There should be no constructor because they should go through the essentially whatever you call it, but essentially the get instance method on the class. That's how you should get an instance. You shouldn't be able to create one because if you do, then you break the instance management part of that class. There are, we'll talk about when we talk about destructors, we'll get a little bit more into it, but there are also things that you do or require that make it a situation where you really shouldn't in the constructor do some things and instead you, I guess you could have a variation of constructor, but it makes more sense to have that initializer method. Most commonly that's going to be if there are resources that an instance uses, for example, if it opens a file and that file stays open through some life cycle of the instance, then you may not want it to always open a file, which would be part of maybe the constructor. Instead you would have an initializer that goes in and opens those resources. Likewise you may have some sort of a pause or something like that, a de-initializer in a sense that essentially does the close. You do see this on file objects, file classes, where a lot of times you maybe for example have a constructor that you give it a name and it says, okay, you have a file of this name, but it hasn't actually opened it or done something with it. It waits for you to either do a create or an open and then the file is open and then somewhere along the way you have a file close that closes the file. You can do that explicitly outside of like a destructor or something like that. We'll talk about that a little bit more when we get into the destructor side, probably next episode. For this one, this episode I really just wanted to talk about the idea of constructors, simple ones versus more complicated ones and initializers to get you thinking about how this class that I'm creating is going to be used so that you have the proper balance of either basically of populating the data within that instance. To make sure that for your required fields you have a way to imply to a developer if not within the documentation to say, hey, here's the things you're probably going to want to use, but also to have an ability to say, okay, if you need an instance and you want to sort of work with it yourself that maybe you don't have all the requirements at once or something like that, then we're going to allow that. Challenge of the week is take a look at the constructors of some of the classes you've been working on lately. Do you have an empty constructor, one where you don't set up parameters? Do you have maybe multiple parameterized constructors that are, we'll call them essentially different contexts for how the class should be used, how those instances will be used? Because certain properties and attributes and parameters that you send in are going to change around a little bit. A good example, commonly you may see something where you have a direct values that you can send, like that address thing. You send that city, state, zip address line. But maybe you also have one that's like a parse, essentially that's a constructor for the address where you send it a string and it goes into the string and parses it out and assigns out the values as needed. A phone number would probably be a better example is that you send it a string. You can either give it the prefix, the main, and I guess the postfix, the area code, the body and the postfix of it. Or you send it a string that maybe those 10 digits or it may be like 3-3-4 or 3.3.4 or something like that. Then you have these constructors that work through it. That being said, we'll wrap it up for today. Go out there, have yourself a great day, a great week, and we will talk to you next time. Thank you for listening to Building Better Developers, the Developer Noir podcast. For more episodes like this one, you can find us on Apple Podcasts, Stitcher, Amazon, and other podcast venues or visit our site at developernoir.com. Just a step forward today is still progress, so let's keep moving forward together.