I have two types, each with a bunch of supporting functions; the entire content of these two types should be private (in my case, they are mutable pointers to objects in C). These two types are conceptually different, so I put them in different modules…
pub mod client {
pub struct Client {
// private internals
}
// Lots of code.
}
pub mod collection {
pub struct Collection {
// private internals
}
// Lots of code.
}
(In my real-world case, mod client and mod collection are separate files, i.e., client.rs and collection.rs.)
client.rs needs to create a Collection; however, it can't, because the internals are private. Any attempt to write a function suffers the same problem: the function would need to be in collection.rs (to access the private members of Collection, but would need to be pub so that client.rs can access it… but now it's also pub to the entire world.
What I'd really like is some sort of crate-level visibility, or a way to "friend" this struct out to another module. (Otherwise, the publically visible stuff in the crate doesn't represent the API, which seems silly.)
Move Collection to a new private module (e.g. collection_impl). Add a public function in that module to create a Collection. Re-export Collection from collection (which is public) with pub use.
You can use collection_impl from within your crate, but since it is private, other crates cannot use it. However, by re-exporting Collection in module collection, other crates can use Collection through this path.
pub mod client {
use super::collection;
use super::collection_impl;
pub struct Client {
p: i32
}
/* this could also be a method on Client */
pub fn make_collection(client: &Client) -> collection::Collection {
collection_impl::new_collection(42)
}
}
mod collection_impl {
pub struct Collection {
p: i32
}
pub fn new_collection(p: i32) -> Collection {
Collection { p: p }
}
}
pub mod collection {
use super::collection_impl;
pub use collection_impl::Collection;
}
If you compare Rust and C++ you will notice that Rust does not have:
protected
friend
This is a deliberate design, and there is no alternative. In Rust something is either private or public, and therefore you do not have to jump all around the codebase to know whether an invariant holds or not.
Therefore, the solution is to:
make a pub fn new function to create a Collection
reinforce this function so it is perfectly safe to use by the whole world
This is actually good design; if there is one struct that should be responsible for upholding Collection's invariants, it certainly is Collection itself. Delegating this responsibility to another crate seems hazardous.
Related
I would like to understand which is the proper way of structuring my code. I have created a Singleton class for video processing (detecting silences) and storing its processing output (the silence timestamps and other info) as a Struct. As this should be a single reference in the whole program, I am using a Singleton pattern, as I will run some multithreading tasks after this one and want to have a single source of truth for that class.
class SilenceDetector {
static let shared = SilenceDetector() // Singleton-pattern
// <-- should I init it?
func detectSilence(videoURL: URL) -> SilencesInfo { ... }
private struct Silence {...}
struct SilencesInfo { // <-- Should I use a Singleton-class?
// here I run different functions with Silence struct
...
I then use SilenceDetector.shared.detectSilence() but to my surprise I cannot access SilenceDetector.shared.SilenceInfo... but SilenceDetector.SilenceInfo.
Whats the proper way of doing it?
There is no proper way of using the singleton pattern. It was always a hack, but has been made completely obsolete by the SwiftUI environment.
Your SilenceDetector should be an EnvironmentObject, whether or not you're using SwiftUI Views.
I have some swift extensions I want to across projects.
I'd like to avoid category pollution though, unless those extensions are requested.
Is it possible to write them so that they only apply if I've done a certain import, like:
import MySwiftExtensions
// Use custom extensions
let x = [1,3,5,7].average()
let y = [1,3,5,7].firstWhere { $0 > 3 }
let z = "campervan".make1337()
I could write these as static methods wrapped in a single letter class (eg: ø.average([1,3,5,7]), like lodash) to achieve the same thing but sometimes you get much more concise usage from instance methods.
You wrote:
I have some swift extensions I want to across projects...
When I have code that I want to use across projects I create a separate framework to hold that code. Then, when I want to use that code in a new project, I embed the framework in that project. Or, for development purposes, I create a workspace that includes the project and the framework. That allows me to work on both at the same time, and then only embed the framework in the final product when it is time to export it.
Once the framework is either embedded or in the same workspace, then you should be able to import it into any individual file in your project with:
import MySwiftExtensions
Any file that does not have the import statement will not have access to the extensions.
EDIT:
Here is a link to a blog that describes how to create a Cocoa Touch Framework. And here is another link that describes in detail how to use workspaces to use frameworks in development projects.
I would like to focus attention on what you reported: "..only apply if I've done a certain import.."
It would also mean you want these extensions can be applyed only to a specific class
As reported in this interesting Apple blog chapter and in the official Apple doc you can handle the "Access Control" of your extension
You can extend a class, structure, or enumeration in any access
context in which the class, structure, or enumeration is available.
Any type members added in an extension have the same default access
level as type members declared in the original type being extended. If
you extend a public or internal type, any new type members you add
will have a default access level of internal. If you extend a private
type, any new type members you add will have a default access level of
private.
Alternatively, you can mark an extension with an explicit access level
modifier (for example, private extension) to set a new default access
level for all members defined within the extension. This new default
can still be overridden within the extension for individual type
members.
/* no access level modifier: default access level will be 'internal' */
extension UIViewSubClass
{
// default access level used: internal
var helloWorld : String {
get {
return "helloWorld"
}
}
}
// modify default access level to public
public extension UIViewSubClass
{
// default access level used: public
var helloWorld : String {
get {
return "helloWorld"
}
}
}
The members of extensions marked private are available within the file where they’re defined, and are not available outside that file. Outside the file where the private extension members were defined, any attempt to use them results in an error, and auto-complete wouldn’t even list them
// modify default access level to private
private extension UIViewSubClass
{
var helloWorld : String {
get {
return "helloWorld"
}
}
}
I don't believe you can do what you want per se, but I've used the following approach to provide functionality to only the specific class that implements an interface:
protocol ExampleProtocol {
}
extension ExampleProtocol where Self: UIViewController{
// extend what you need to here
}
Implementations of rx provide BehaviorSubject<T> and Variable<T> as mechanisms for modeling properties that change over time (a useful replacement for C# INotifyPropertyChanged).
Generally these are exposed as Observable<T> but it would be more useful to expose properties as something like:
class ObservableValue<T> : Observable<T>{
var currentValue:T { get }
}
This can be created along these lines in swift:
class ObservableValue<Element> : ObservableType {
typealias E = Element
private let subject:BehaviorSubject<E>
var currentValue:E {
get {
return try! subject.value()
}
}
init(subject:BehaviorSubject<E>) {
self.subject = subject
}
func subscribe<O: ObserverType where O.E == E>(observer: O) -> Disposable {
return self.subject.subscribe(observer)
}
}
Does this already exist? and if not is it because it's against the aims of Rx?
The only way around it is to expose a separate currentValue or write consumers that assume the concrete implementation behind the exposed Observable is a BehaviourSubject or somewhere in the chain a replay() has occured e.g. the following snippet doesn't make it explicit that as soon as I subscribe I will get a value:
class MyViewModel {
// 'I will notify you of changes perhaps including my current value'
myProperty:Observable<String>
}
so code has to be written as if its 'asynchronous' with an underlying assumption it will act in an almost synchronous manner rather than:
class MyViewModel {
// 'I have a current value and will notify you of changes going forward'
myProperty:ObservableValue<String>
}
Having thought it over and discussed it a bit more presumably the reason it doesn't (and perhaps shouldn't exist) is that it's an introduction of imperatively accessed state.
Other mechanisms of maintaining state (such as scan) do so within the confines of chained observables rather than as 'dead-end' direct calls such as 'give me the value right now'.
Perhaps it would have it's place in a hybrid reactive/imperative approach but it may just hinder full embracement of the reactive style.
It's analogous to using promises or tasks in half of the code then reverting to synchronous blocking code in other parts.
In most cases what people do is create a standard view model that exposes properties via INotifyPropertyChanged. This allows UI elements to bind to them and receive property change events and keep the UI in sync.
Then if you want an IObservable for said property you take advantage of standard Rx operators that turn events into IObservable. You can google this to find lots of different implementations. You would generally create and consume these observables from something that is observing the view model rather than expose them on the view model directly.
We have a lot of blogs, where Swift and it's awesomeness is discussed. Most of them sound like a whole WWDC and don't discuss their topics in an exhausting way and a critical point of view. So this question is explicit for the free thinking minds, the stackoverflow community ;-)
In Swift we have access control mechanisms like
public private(set) var foo: Foo?
and
private var _foo: Foo?
public var foo: Foo? {
get {
// make some preparing stuff, in another kind of way, as in the setter
return _foo
// make some completing stuff, in another kind of way, as in the setter
}
willSet {
// make some preparing stuff
}
set {
_foo = newValue
}
didSet {
// make some completing stuff
}
The common way in OOP for this purpose is
private var foo: Foo?
public getFoo() -> Foo? {
// make some preparing stuff, in the same kind of way, as in the setter
return foo
// make some completing stuff, in the same kind of way, as in the setter
}
private setFoo(foo: Foo) {
// make some preparing stuff
self.foo = foo
// make some completing stuff
}
What do you think about these mechanisms, considering following questions?
Why willSetand didSet but no willGetand didGet?
Is there no better way than these double defining variables fooand _foo?
public private(set) gives good access control, but the IDE Xcode shows suggestions to the variable, when typing myInstance.foo = from outside the declaring class. No Error or warning is shown until you assign a new value.
After assigning the new value, Xcode says the setter is inaccessible. In OOP usually visibility is checked at first. Swift seems not to know what visibility is. Obviously it's not possible to determine if myInstance.foo will be completed to an "read command" myInstance.foo.bar or a "write command". What do you think about this lack of useful code completion?
Has anyone doe's performance checks aiming at the use of explicit getters and setters?
Is it a good idea to use computed variables. They are in fact nothing else than the results of methods/functions.
Apple and it's community promote the meaningfulness or awesomeness of these techniques intensively. a) Is it bad to use traditional Getters and Setters? b) Why does Apple use "their" approach in common iOS UserInterface Classes (textField.text = "foo"), in contrast to their youngest classes in the UserInterface of the WatchKit (textField.setText("foo"))? Is it a step back of forward?
So. These are many questions, but I thinks, at least these are relevant, to get an overview. I'm looking forward for your aspects.
Mutations are queries for manipulating data. If so then my root query and root mutation tree should look similar right? They both should allow nested fields (nested mutations). I was playing with this (using express-graphql) and it works.
Example:
// PUT /projects/:project_id/products/:id
mutation {
findProject(id: 1) { // make sure that project exists and we can access it before mutating data
updateProduct(id: 1, name: "Foo") { // the resolve function receives a valid `project` as the first argument
id
}
}
}
Is this a valid example? Should mutations be nested like this? If no, how should I handle nested resources? I can not find any real-life example that would mutate nested resources. All examples define mutations only on the first level (fields on the root mutation).
The product has a unique ID, so that's all you need to identify it.
mutation {
updateProduct(id: 1, name: "Foo") {
id
}
}
To verify that the user is authorized to modify the product, you should check the products' project. You'd probably have some centralized authorization anyway:
resolve({ id }, { user }) {
authorize(user, 'project', Product.find(id).project) // or whatever
... // update
}
Old answer:
This is certainly a valid example.
I'd guess the lack of nested object mutation examples may be due to the fact that even if a product is linked to a project, it would in most cases still have a unique ID -- so you can find the product even without the project id.
Another alternative would be to include the project id as an argument to updateProduct:
mutation {
updateProduct(projectId: 1, id: 1, name: "Foo") {
id
}
}
Your solution seems nicer to me, though.
As a note, mutations are, in fact, exactly the same as queries. The only difference is that the resolve function typically includes some permanent change, like modifying some data. Even then though, the mutation behaves just like a query would -- validate args, call resolve function, return data of the declared type.
We declare such method as a mutation (and not a query) to make explicit that some data are going to be changed but also for the more important reason: The order in which you modify data is important. If you declare multiple mutations in one request, the executor will run them sequentially to maintain consistency (this doesn't attempt to solve distributed writes though, that's a whole another problem).