Swift access control on computed properties: why does this work? [duplicate] - swift

This question already has answers here:
Private var is accessible from outside the class
(2 answers)
Closed 6 years ago.
I seem to be misunderstanding something about access control modifiers in Swift. Here is my code from a playground:
class Something {
private (set) var name :String {
get { return "" }
set {}
}
}
var thing = Something();
thing.name = "";
My intuition and experience from other languages tells me that there should be a compiler error on the last line.
The book I'm learning from however states that private means the member being modified is only accessible from the same source file.
Am I safe to assume this scenario would generally be an error in most projects, and this is only because I'm running this code in a playground?
Is the statement that private members can only be accessed from the same source file totally accurate?

This rule is valid for all versions of Swift 2. It is valid for your example as well, and worked because your setter code is in the same file (if I understand your example correctly) in which the setter was invoked.
The top-level assignment expression thing.name = ""; was allowed because it is running in a playground. Outside playgrounds, this particular top-level assignment would be illegal in most cases (there are exceptions!).
Bonus explanation of what constitutes as "top-level code" and where it is applicable; from the official Swift blog here:
However, top-level code is not allowed in most of your Swift source
files. For clarity, any executable statement not written within a
function body, within a class, or otherwise encapsulated is considered
top-level. We have this rule because if top-level code were allowed in
all your files, it would be hard to determine where to start the
program.
...
You’ll notice that earlier we said top-level code isn’t allowed in
most of your app’s source files. The exception is a special file named
“main.swift”, which behaves much like a playground file, but is built
with your app’s source code. The “main.swift” file can contain
top-level code, and the order-dependent rules apply as well. In
effect, the first line of code to run in “main.swift” is implicitly
defined as the main entrypoint for the program. This allows the
minimal Swift program to be a single line — as long as that line is in
“main.swift”.

The book I'm learning from however states that private means the member being modified is only accessible from the same source file.
And your example is accessing it from the same source file. What's the issue?
In Swift 3, private becomes fileprivate, wherein access is allowed anywhere from the same file. private in Swift 3 has the behavior you expect, where access is only allowed within the class/struct/enum itself.

Related

How to avoid not used function to be wiped out by optimizer

While compiling and Xcode swift project for MacOS, not used functions are removed from the binary (removed by the optimizer I guess). Is there a way to tell the compiler to not remove unused functions, perhaps with a compiler option (--force-attribute?) so that even with optimization enabled those functions remain in the binary?
I know that if a global function is declared as public (public func test()) then it's not removed even if not used (Since it can be used by other modules), but I can't use public since that would export the symbol for that function.
Any suggestion?
If this is indeed removed by the optimiser, then the answer is two-fold.
The optimiser removes only things that it can prove are safely removable. So to make it not remove something, you remove something that the optimiser uses to prove removability.
For example, you can change the visibility of a function in the .bc file by running a pass that makes the functions externally callable. When a function is private to the .bc file (also called module) and not used, then the compiler can prove that nothing will ever call it. If it's visible beyong the .bc file, then the compiler must assume that something can come along later and call it, so the function has to be left alive.
This is really the generic answer to how to prevent an optimisation: Prevent the compiler from inferring that the optimisation is safe.
Writing and invoking a suitable pass is left as an exercise for the reader. Writing should be perhaps 20 lines of code, invoking… might be simple, or not, it depends on your setting. Quite often you can add a call to opt to your build system.
As I discovered, the solution here is to use a magic compiler flag -enable-private-imports (described here: "...Allows this module's internal and private API to be accessed") which basically add the function name to the list #llvm.used that you can see in the bitcode, the purpose of the list is:
If a symbol appears in the #llvm.used list, then the compiler,
assembler, and linker are required to treat the symbol as if there is
a reference to the symbol that it cannot see (which is why they have
to be named)
(cit.) As described here.
This solves my original problem as the private function even if not used anywhere and not being public, during compilation is not stripped out by the optimiser.

What is the scope of extensions in swift?

I'm learning the swift programming language and recently came across the concept of extensions, where you can extend the functionality of an existing class or struct. For example (source):
extension String {
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
My question is, other than the file where I write this, what other code does this modification impact?
For example, if I declare an extension to String in one file, will it affect the behavior of String in libraries I import? Or if I declare this extension in one file, will it be visible in other files in the same project?
Relatedly, I don't understand how Swift resolves conflicts between extensions. Say for example, I import two libraries which both extend String. Which one takes effect?
I have tried Googling for terms like "swift extensions scope" and "swift conflicting extensions", and haven't found anything that describes fully how it works. I have also noticed Swift doesn't let me redeclare an extension within a single file, but that doesn't answer my question about how extensions from imports affect each other.
The scope of an extension follows the same rules as when creating structs, classes and other types and variables in swift.
By default the extension is internal to the module it is created in and so accessible to all files in that module.
You can change that to public or private if you wish to.
The collisions you reference would occur if two extensions of the same were visible to each other and added a function with the same signature.
So, if you wanted to create your trimmed() extension in several files and give it a different implementation in each file you would need to make them all private to avoid any conflict.
Although… that might not be a good idea as it could be quite confusing with several of these in your project.

Why do powershell class properties require this within their methods?

PSVersion: 5.1.17134.858
I haven't done a whole lot of work with Powershell's classes but here's a simple example of what I'm running into:
class xNode{
[uint64]$MyID=0
static [uint64]$ClassID=0
xNode(){
$MyID = [xNode]::ClassID++
}
[String] ToString(){return "xNode: $MyID"}
}
doesn't parse it gives the two errors:line 6 $MyID..., "Cannot assign property, use '$this.MyID'."line 9 ..$MyID", "Variable is not assigned in the method."
I'm trying to use the classes property named $MyID, and this usage appears to be in line with the example given in the help documentation get-help about_Classes, and when I copied their whole example at the end out to a file then tried to run it I was getting the same errors as well for $Head, $Body, $Title,... Of course I can force it to work by adding this.
class xNode{
[uint64]$MyID=0
static [uint64]$ClassID=0
xNode(){
$this.MyID = [xNode]::ClassID++
}
[String] ToString(){return "xNode: $($this.MyID)"}
}
However I'd rather not have to keep typing this. all over the place, is there maybe some environment setting or something I've overlooked?
(Note: to get it to work at the commandline, I also needed to remove all of the blank lines)
However I'd rather not have to keep typing this. all over the place, is there maybe some environment setting or something I've overlooked?
No, it's working as advertised, you can't reference instance properties inside the class without the $this variable reference.
Why do powershell class properties require this within their methods?
(The following is what I'd call "qualified speculation", ie. not an officially sourced explanation)
PowerShell classes are a bit tricky from an implementers point of view, because a .NET property behaves differently than, say, a parameter in a powershell scriptblock or a regular variable.
This means that when the language engine parses, analyzes and compiles the code that makes up your PowerShell Class, extra care has to be taken as to which rules and constraints apply to either.
By requiring all "instance-plumbing" to be routed through $this, this problem of observing one set of rules for class members vs everything else becomes much smaller in scope, and existing editor tools can continue to (sort of) work with very little change.
From a user perspective, requiring $this also helps prevent accidental mishaps, like overwriting instance members when creating new local variables.

What does it mean , when we say private instance variable for its own library?

I am beginner to flutter/dart and has read that we don't have public/private/protected access specifier for dart but if we want to make private instance variable, we can make the use of underscore(_) operator but it will not make the variable private to the class but to its own library, So what does it actually mean ?
Dart privacy is indeed only on a per library basis.
A name which begins with _ is a library private name. A private identifier, like _tmp, is considered a different name than a similarly spelled identifier, also _tmp, which occurs in a different library.
That means that code in a different library cannot access the private name _tmp because it can't even express it. If it tries to write _tmp, it can only refer to a private name of its own library instead.
The choice of embedding access control in the name makes sense when you remember that Dart has dynamic invocations. If you write dynamic x = ...; x.foo();, then this should call the foo method of x if there is one. To do this efficiently, it would be too much of an overhead if each dynamic invocation should also figure out where the name originally comes from and whether it's accessible to the caller. Dart avoids this overhead by making all public names visible, and all private names inexpressible.
The goal of privacy is to separate public interface API from internal implementation API, and to avoid naming conflicts.
You can write your private names without fear that they conflict with someone else's names, and without risking someone thinking they are meant for public use.
Dart does not try to protect code from other code in the same library. It's supposed to be the same author anyway, so they can be trusted to use the API responsibly (and if not, it's on themselves).
What it means for you as a user is: The library is the unit of code. You can make libraries which contains only a single class. The library privacy is class privacy for that class. Or you can create libraries with many classes and top-level functions which can all see each other's private names.
That means you should base your modularity on the need of classes to share implementation, and not really anything else. You can always build a larger API by exporting other libraries.
When creating a Pub package, I would create your own internal libraries, inside the lib/src/ directory, giving them whatever size is convenient, and then export your public API from the package main file in lib/.
a library/module/model refferes to the class itself, so any variables/methods are only accessable to the class itself. any class from the outside world trying to access this property, will not be able to. basically its own library means the class itself

Why would identical code throw an error in one location but not another?

I'm currently starting up work on a project, and my first task is decomposing a God Object that someone else created out of the AppDelegate. I've started by copying code related around managing location out, in the intention of delegating calls to that code into the new object.
I have two statements that are driving me nuts however.
New file:
if locationManager?.location?.horizontalAccuracy > horizontalAccuracyCheck{...}
Old file:
if locationManager?.location?.horizontalAccuracy > horizontalAccuracyCheck{...}
You'll notice the code is identical. In both cases self.locationManager? is defined as:
var locationManager: CLLocationManager?
But in the new file, I'm getting a warning about 'value of optional type no unwrapped' -- why? Exact duplicate code, copied & pasted, what would make this different?
Changing the code to unwrap it fixes things:
if (locationManager?.location?.horizontalAccuracy)! > horizontalAccuracyCheck{...}
I can wrap my head around why I need to explicitly unwrap a potentially optional return. But... why only in one place?
The reason is that we're talking here about two quite different languages. One file is Swift 2, the other file is Swift 3.
In Swift 2, you can compare an Optional representing a number with another number using the greater-than or less-than operator. In Swift 3, you can't do that.
Here's a simpler example of the same thing:
let optint : Int? = 7
let ok = optint < 42
That code is legal in Swift 2 but illegal in Swift 3.
As discussed in this Q&A – the Swift migrator will insert a custom fileprivate operator overload in order to allow for optional comparisons to work in Swift 3 the same way they did in Swift 2. Because this overload is fileprivate, you won't be able to use it from any other source files in your project that don't also define it, thus why your comparison fails to compile in the new source file.
Therefore one solution is just to copy it over to your new file. Another is to remove the fileprivate access modifer. The overload will default to internal, and therefore be accessible to other Swift files in your module.
Although really I would just recommend removing the overload entirely and instead write your own explicit logic for optional comparison when it arises – the overload can be too easily misused (as demonstrated by the Swift evolution proposal to remove it).