Best Practices: description vs debugDescription - swift

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.

Related

Swift Core Data Usage in Xcode

I am relatively new to Swift Programming and recently tried out Core Data for the first time. However, I am having a hard time understanding several (for me) strange behaviours I am encountering:
I have create all my entities and their attributes in the ".xcdatamodeld" file. Codegen is on "Manual/None". Some of the attributes are marked a non-optional. Still, when I generate the NSManagedObject Subclass files, I still see them as optional in the "...Properties" files, i.e. having a "?" after the type. Why is that?
Somewhat relating/in contrast to the first bullets, the attributes for some entities do not have the "?", although they are marked as optional. When I try to add the "?", I get an error "Property cannot be marked #NSManaged because its type cannot be represented in Objective-C". Why is that?
When I'm creating the NSManagedObject Subclasses and select some subfolder in my project for them to be created in, they are put at the top of the hierarchy tree, regardless.
What happens if I change information in the "...Class"/"...Properties" files generated by Core Data which would conflict with what is in the ".xcdatamodeld" file. What takes precedence? How are they related?
In general I find there is not much detailed descriptions available on Core Data except introductory things. Would anyone know some good resources on that? Website? Youtube Videos? Books?
Answers:
Creating the subclasses manually treates the optionals not accurately. Check any attribute and remove the question mark in the class if it's non-optional in the model.
Scalar Swift optional types (Int?, Double?, Bool?) cannot be represented in Objective-C. I recommend to declare them as non-optional.
Never mind, it has no effect where the classes are located, the main thing is that the file name is black (valid) in the Project Navigator and the target membership is assigned correctly.
in the Codegen Manual / None case you are responsible that the types in the model match the types in the classes otherwise you could get unexpected behavior. Any change in the class must be done also in the model and vice versa. However you can replace suggested ObjC classes like NSSet or NSDate with native Swift types Set<MyClass> or Date without changing the type in the model.

What's the correct way of thinking C# protected accessor in swift?

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.

Any reason not use use a singleton "variable" in Swift?

For Sept 2015, here's exactly how you make a singleton in Swift:
public class Model
{
static let shared = Model()
// ( for ocd friends ... private init() {} )
func test()->Double { print("yo") }
}
then elsewhere...
blah blah
Model.shared.test()
No problem.
However. I add this little thing...
public let model = Model.shared
public class Model
{
static let shared = Model()
func test()->Double { print("yo") }
}
then, you can simply do the following project-wide:
blah blah
model.test()
Conventional idiom:
You see Model.shared.blah() everywhere in the code.
"My" idiom:
You see model.blah() everywhere in the code.
So, this results in everything looking pretty!
This then, is a "macro-like" idiom.
The only purpose of which is to make the code look pretty.
Simplifying appearances of ImportantSystem.SharedImportantSystem down to importantSystem. throughout the project.
Can anyone see any problems with this idiom?
Problems may be technical, stylistic, or any other category, so long as they are really deep.
As a random example, here's an "article in singletons in Swift" that happens to also suggest the idea: https://theswiftdev.com/swift-singleton-design-pattern/
Functionally, these are very similar, but I'd advise using the Model.shared syntax because that makes it absolutely clear, wherever you use it, that you're dealing with a singleton, whereas if you just have that model global floating out there, it's not clear what you're dealing with.
Also, with globals (esp with simple name like "model"), you risk of having some future class that has similarly named variables and accidentally reference the wrong one.
For a discussion about the general considerations regarding globals v singletons v other patterns, see Global Variables Are Bad which, despite the fairly leading title, presents a sober discussion, has some interesting links and presents alternatives.
By the way, for your "OCD friends" (within which I guess I must count myself, because I think it's best practice), not only would declare init to be private, but you'd probably declare the whole class to be final, to avoid subclassing (at which point it becomes ambiguous to what shared references).
There are a few things to look out for when using this approach:
The global variable
A global variable in itself is no big deal, but if you have quite some global variables, you might have trouble with autocompletion, because it will always suggest these global variables.
Another problem with global variables is that you could have another module in your application (written by you or otherwise) define the same global variable. This causes problems when using these 2 modules together. This can be solved by using a prefix, like the initials of your app.
Using global variables is generally considered bad practice.
The singleton pattern
A singleton is helpful when working with a controller, or a repository. It is once created, and it creates everything it depends on. There can be only one controller, and it opens only one connection to the database. This avoids a lot of trouble when working with resources or variables that need to be accessed from throughout your app.
There are downsides however, such as testability. When a class uses a singleton, that class' behaviour is now impacted by the singletons behaviour.
Another possible issue is thread safety. When accessing a singleton from different threads without locking, problems may arise that are difficult to debug.
Summary
You should watch out when defining global variables and working with singletons. With the appropriate care, not many problems should arise.
I can't see a single downside to this approach:
You can use different variables for different parts of the program (-> No namespace cramming if you don't like this I guess)
It's short, pretty, easy to use and makes sense when you read it. Model.shared.test() doesn't really make sense if you think about it, you just want to call test, why would I need to call shared when I just need a function.
It uses Swift's lazy global namespace: The class gets allocated and initialized when you use it the first time; if you never use it, it doesn't even get alloced/inited.
In general, setting aside the exact idiom under discussion, regarding the use of singletons:
Recall that, of course, instead of using static var shared = Model() as a kind of macro to a singleton, as suggested in this Q, you can just define let model = Model() which simply creates a normal global (unrelated to singletons).
With Swift singletons, there has been discussion that arguably you want to add a private init() {} to your class, so that it only gets initialized once (noting that init could still be called in the same file).
Of course in general, when considering use of a singleton, if you don't really need a state and the class instance itself, you can simply use static functions/properties instead. It's a common mistake to use a singleton (for say "calculation-like" functions) where all that is needed is a static method.

Intersystems Cache - Correct syntax for %ListOfObjects

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.

Classes: Public vars or public functions to change local vars?

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.