Exactly what the topic title says,
In which cases would you prefer using public functions to change local variables over just defining that variable as public and modifying it directly?
Don't expose the data members directly: using opaque accessors means you can change the implementation at a later date without changing the interface.
I should know. I take the short cut from time-to-time, and have had occasion to regret it.
Obviously if you want changing the variable to have some other effect on the object's state (like recalculating some other property of the object) you must use a mutator function.
If it's possible to set the variable to something that places the object in an invalid state, you should probably also use a mutator function. This way you can throw an exception (or return an error, or just ignore) if something illegal is about to happen. This does wonders for debugging.
But if some variables can be modified with mutator functions, and others are public, the programmer needs to keep track of which is which. This is a waste of time and effort so in some cases it's easiest to just use mutator functions for everything.
If you look at an object purely in term of service, you realize that exposing a variable is not a good way to expose those services.
The API must reflect what the object is all about (for it to achieve a high cohesiveness), and if you define a setValue(...), it is not so much because you need a way to -- today -- changes a variable, but because it makes sense for the object to expose this service.
So:
Don't provide accessors or mutator function to every single member of every single class you write. Only provide accessors/mutator functions if the accessors/mutator methods are a sensible and useful part of the class's interface (API).
Don't think of these methods as accessors or mutators. Instead, think of them as methods that access or mutate a certain abstract property of the object that happens to be represented by a single member today, but may be computed in a more complex manner tomorrow.
You should mention what language you are dealing with, since that will affect the answer.
Your first thought should be about the API to your class. If you want to keep that API stable (and you should!), then consider how you might change today's simple variable into a full-blown method later.
In many languages, you can't change a variable to a method without changing the calling code. C, C++, and Java fall into this category. Never use public variables in these languages, because you won't have any wiggle room later.
In Python, you can change a variable to a property without changing the callers, so you don't have to worry up front: use public variables.
C# I believe has properties that can let you change variables to methods transparently, but I am not sure.
If you want to change a variable inside a class, your best doing it through Properties.
Its not good practice to have variable's modified on the outside.
Think of future development too. You could put some logic behind a Property without changing the whole program.
Related
Headline: description called by super.init()
This is a new take on an old question. As a primarily Swift programmer I tend to not use NSObject for class definitions because of the residual side effects of Objective-C. Like if I have a read-only property called length and I then want to create a setter function called setLength, I get warnings about it conflicting with a similar definition from Objective-C. I just discovered the set(var){} setter. If I subclass a Cacoa class like UIDocument, etc. that inherit from NSObject, I have to live with these side effects.
I have a class that uses two other classes in the property definitions, none of them NSObjects. This class has a description computed variable that uses the description computed variables for the other two classes in its composition. All three classes need to conform to the CustomStringConvertable protocol. Ok, everything is good.
At some point this class got upgraded to being a UIDocument and the CustomStringConvertable became redundant and was removed. Everything still works.
Here is what I found out today. I wanted to break at a point in the program where it was printing one of the two properties and as a convenience I set the break point in the description variable for that class, thinking that it should only be called at the point I am interested in, where it is printed out. What I discovered is that the description variable gets called during all the super.init() of the UIDocument sub-class! And there were a few of them. I think composing strings as being relatively expensive but didn't care because they were only used in debug, but with them being called and who knows how they are used in super.init(), I need to change this.
I checked another UIDocument class in the same program that has 200 files associated with it and it is also calling description in super.init().
Does anyone have any input on the Best Practices for using description vs debugDescription?
I'm going to answer my own question as a matter of documentation.
I switched the UIDocuments subclasses to define and use debugDescription. I am debugging some code that loads all the files and does some manipulation and I was able to reduce the load time from 9.8 seconds to 6.8 seconds.
I also went through all the places where the Swift 3 conversion added String(describing:) to the program and found I could change a lot of them to using debugDescription and eliminate the String(describing:) wrapper.
I think the best practice is to only define and use debugDescription and for my non-NSObjects change conformance from CustomStringConvertable to CustomDebugStringConvertable.
In swift, how is constants implemented?
I read this article, which says
In Swift, constants are generally implemented as (inlined) function calls.
I am not clear of this statement.
Does Swift use a special approach to make constants?
Could anyone explain?
Are you familiar with "getter" and "setter" methods from other languages, such as Java? If a variable is made public in a language like Java, it's exposed to other classes to access directly. In the future, if this variable has to be changed, there's no way to do so without changing all of the other classes dependent upon. With getter/setter methods, dummy implementations can be made that don't do anything besides read/write the value. In the case that a change needs to be made, the implementation of these methods can be changed without effecting the public API of the class.
Swift implements variables with "properties", which are like a backing private variable with public getter/setter methods that are automatically generated. In the future, you can replace a property with a computer property with a special getter/setter implementation, without effecting the public API of the class, just like before. The difference here is that you don't need to write all of the default getters/setters yourself.
In c# we have the protected accessor which allows class members to be visible on inherited clases but not for the rest.
In Swift this doesn't exist so I wonder what's a correct approach for something like this:
I want to have a variable (internal behavior) and and a public method using this variable on a base class. This variable will be used also on inherited clases.
Options I see
Forget about base class and implement variable and methods everywhere I need it. WRONG, duplicated code
Implement inheritance by composition. I'd create a class containing common methods and this will be used by composition instead of inheritance. LESS WRONG but still repeating code that could be avoided with inheritance
Implement inheritance and make variable internal on base class. WRONG since exposes things without any justification except allowing visibility on inherited clases.
Implementation Details for Base Class
I want to have a NSOperationQueue instance and and a public method to cancel queued operations. I add new operations to this queue from inherited classes.
In Swift the correct answer is almost always protocols and extensions. It is almost never inheritance. Sometimes Cocoa stands in our way, because there are classes in Cocoa more often than protocols, but the goal is almost always protocols and extensions. Subclassing is our last choice.
Your particular case is confusing because NSOperationQueue already has a public method to cancel queued operations (cancelAllOperations). If you want to protect the queue from outside access (prevent callers from using addOperation directly for instance), then you should put the queue inside another type (i.e. composition), and forward what you want to the queue. More details on the specific problem you're solving would allow us to help suggest other Swift-like solutions.
If in the end you need something that looks like protected or friend, the correct solution is private. Put your subclass or your friend in the same file with the target, and mark the private thing private. Alternately, put the things that need to work together in a framework, and mark the attribute internal. The Swift Blog provides a good explanation of why this is an intentional choice.
I want to define global methods.
For that i define their signature under global unit.
What are the disadvantages of doing so ?
Why does it not recommended ?
One disadvantage of using global methods might be that they can be called without explicitly stating the object (just foo() rather than global.foo()), and this is error prone. For example, if your struct happens to have its own method with the same name, such a call is treated as a call to the struct method rather than the global method.
Speaking more generally, one of the principles in object oriented programming is that functions (methods) belong to some object/class rather than being global.
I recommend using sn_utils instead. It is also a singleton like global, but forces you to use its instance name: utils.foo().
You need to be aware not to pollute its namespace, e.g. use <evc-name>_foo() as method name.
The documentation says this is allowed:
ClassMethod GetContacts() As %ListOfObjects(ELEMENTTYPE="ContactDB.Contact")
[WebMethod]
I want to do this:
Property Permissions As %ListOfObjects(ELEMENTTYPE="MyPackage.MyClass");
I get an error:
ERROR #5480: Property parameter not declared:
MyPackage.Myclass:ELEMENTTYPE
So, do I really have to create a new class and set the ELEMENTTYPE parameter in it for each list I need?
Correct syntax for %ListOfObjects in properties is this one
Property Permissions As list of MyPackage.MyClass;
Yes, a property does sometimes work differently than a method when it comes to types. That is an issue here, in that you can set a class parameter of the return value of a method declaration in a straightforward way, but that doesn't always work for class parameters on the class of a property.
I don't think the way it does work is documented completely, but here are some of my observations:
You can put in class parameters on a property if the type of the property is a data-type (which are often treated differently than objects).
If you look at the %XML.Adaptor class it has the keyword assignment statement
PropertyClass = %XML.PropertyParameters
This appears to add its parameters to all the properties of the class that declares it as its PropertyClass. This appears to be an example of Intersystems wanting to implement something (an XML adaptor) and realizing the implementation of objects didn't provide it cleanly, so they hacked something new into the class compiler. I can't really find much documentation so it isn't clear if its considered a usable API or an implementation detail subject to breakage.
You might be able to hack something this way - I've never tried anything similar.
A possibly simpler work around might be to initialize the Permissions property in %OnNew and %OnOpen. You will probably want a zero element array at that point anyway, rather than a null.
If you look at the implementation of %ListOfObjects you can see that the class parameter which you are trying to set simply provides a default value for the ElementType property. So after you create an instance of %ListOfObjects you could just set it's ElementType property to the proper element type.
This is a bit annoying, because you have to remember to do it every time by hand, and you might forget. Or a maintainer down the road might not now to do it.
You might hope to maybe make it a little less annoying by creating a generator method that initializes all your properties that need it. This would be easy if Intersystems had some decent system of annotating properties with arbitrary values (so you could know what ElementType to use for each property). But they don't, so you would have to do something like roll your own annotations using an XData block or a class method. This probably isn't worth it unless you have more use cases for annotations than just this one, so I would just do it by hand until that happens, if it ever does.