Swift - Array with specific class type - arrays

How can i create array which will hold objects belonging a specific class.
class BaseObject {}
class Derived1: BaseObject {}
class Derived2: BaseObject {}
class Derived2: BaseObject {}
I need to create array in which will hold only Object derived from BaseObject
Something like - var array : [BaseObject.Type] = []
Is there a way to specify this ?
Also, I should be able to use it something like this
if let derived1 = object as? [Derived1] {
}
else if let derived2 = object as? [Derived2] {
}

You can obviously define your array as an array of BaseObject:
var objects: [BaseObject] = [] // or `var objects = [BaseObject]()`
But it's going to let you create a heterogenous collection (of either BaseObject or Derived1 or Derived2 or of any other subclass). That's a core OO design concept (the Liskov substitution principle) that any subclass of BaseObject should (and will) be permitted.
If all you want is to say that you can only have an array of one of the subtypes, you can obviously just define your array as such, e.g.:
var objects: [Derived1] = []
That will obviously allow only Derived1 objects (and any subclasses of Derived1.
90% of the time, the above is sufficient. But in some cases, you might needs some collection with methods that require some inherited base behavior, but for which you don't want to allow heterogenous collections. In this case, I might consider a more protocol-oriented pattern:
Bottom line, should we be subclassing, or should we be using a protocol-oriented approach? I.e. is BaseObject actually something you'll instantiate for its own purposes, or is it there merely to define some common behavior of the subclasses. If the latter, a protocol might be a better pattern, e.g.:
protocol Fooable {
func foo()
}
// if you want, provide some default implementation for `foo` in an
// protocol extension
extension Fooable {
func foo() {
// does something unique to objects that conform to this protocol
}
}
struct Object1: Fooable {}
struct Object2: Fooable {}
struct Object3: Fooable {}
This yields the sort of behavior that you may have been using in your more OO approach, but using protocols. Specifically, you write one foo method that all of the types that conform to this protocol, e.g., Object1, Object2, etc., can use without having to implement foo themselves (unless, of course, you want to because they need special behavior for some reason).
Because this eliminates the subclassing, this then opens the door for the use of generics and protocols that dictate some generalized behavior while dictating the homogenous nature of the members. For example:
struct FooCollection<T: Fooable> {
private var array = [T]()
mutating func append(_ object: T) {
array.append(object)
}
// and let's assume you need some method for your collection that
// performs some `Fooable` task for each instance
func fooAll() {
array.forEach { $0.foo() }
}
}
This is a generic which is a homogenous collection of objects that conform to your protocol. For example, when you go to use it, you'd declare a particular type of Fooable type to use:
var foo = FooCollection<Object1>()
foo.append(Object1()) // permitted
foo.append(Object2()) // not permitted
foo.fooAll()
Now, I only went down this road because in comments elsewhere, you were inquiring about generics. I'd personally only go down this road if the (a) collection really needed to be homogenous; and (b) the collection also wanted to implement some shared logic common to the protocol. Otherwise, I'd probably just stick with a simple [Derived1] (or [Object1]). The above can be powerful when needed, but is overkill for simpler situations.
For more discussion about protocol oriented programming, the homogenous vs heterogenous behavior, traditional stumbling blocks when you're coming from a traditional OO mindset, I'd refer you to the WWDC 2015 video, Protocol-Oriented Programming in Swift, or it's 2016 companion video that builds upon the 2015 video.
Finally, if you have any additional questions, I'd suggest you edit your question providing details on a practical problem that you're trying to solve with this pattern. Discussions in the abstract are often not fruitful. But if you tell us what the actual problem you're trying to solve with the pattern in your question, it will be a far more constructive conversation.

Related

How does Raku deal with the diamond problem (multiple inheritance)?

So it's no secret that Raku has multiple inheritance, so that got me wondering: "how does Raku deal with that in any reasonable manner?"
Some preliminary testing reveals that default behaviour is inherited from the first class in the inheritance list, that's fine, many other languages do it like that too
class A {
has $.foo = 0;
method speak {...}
}
class B is A {
has $.foo = 1;
method speak {
say 'moo';
}
}
class C is A {
has $.foo = 2;
method speak {
say 'baa';
}
}
class D is B is C {}
class E is C is B {}
say D.new.foo; # prints 1 (from B)
say E.new.foo; # prints 2 (from C)
But that got me wondering, what if I want D to use C's speak?
Due to the inheritance order I get B's by default.
I understand that roles exist to solve this exact issue by facilitating a disambiguation mechanism, but suppose hypothetically I find myself in a situation where I don't have roles at my disposal (boss hates them, inherited a library that doesn't have them, pick your excuse) and really need to disambiguate the inherited classes.
What's the mechanism for dealing with that in Raku?
Generally you would need to provide a tie-breaker method in the class that has the (potential) ambiguity. Fortunately, you do not have to create separate methods, as you can call specific versions of methods in a call.
So the answer to your question: Add a method speak to class D, and have that call the speak method from class C:
class D {
...
method speak { self.C::speak }
}
And for methods taking parameters, take a Capture of all parameters, and pass that on:
class D {
...
method foo(|c) { self.C::foo(|c) }
}
Note that the "c" in |c is just an identifier, it could be any identifier. But it is sorta customary, at least with Raku core developers, to just use |c, with the "c" standing for "capture".
Now, this will cause some overhead, as you would have an extra level of indirection. Should this turn out to be a performance issue, there's some meta-programming you can do to alias the speak method in D to the speak method in C:
class D {
...
BEGIN D.^add_method("speak",C.^find_method("speak"));
}
This will, at compile time because of the BEGIN, add a Method object to the D class called speak that is defined by the speak method of class C. Since this is an alias, you don't have to worry about any parameters being passed.

Replacing array with a class that acts like array but provides type specific functions?

I have a class like this:
export class IManor {
tenants: ITenant[];
But I have some aggregate querying funtionality I'd like off of tenants as well and would like to replace it with a class. I know I can attend Array for this but want to be able to access the interface of contents for the aggregate functions, for something like:
class Tenants extends Array<ITenant> {
totalAcres(): number {
let total = 0;
for (const tenant in this) {
total += tenant.acres;
}
return total;
}
}
but the function doesn't appear to be aware of it's interface. My googling turns up generic array extensions only (and the problems with those).
The goal is to be able to to the normal 'let tenant of manor.tenants' while also doing things like manor.tenants.totalAcres();
Any pointers would be appreciated.
Inheritance of you class from Array<ITenant> doesn't affect your previous definition in any way. If you want you methods to be available in IManor class you have to define tenants member as Tenants. In this case you cannot use array syntax for constructing this entity but new Tenants() instead, but all other array method(like filter, map, etc) will be available as well as your methods like totalAcres.
So IManor definition will look like:
export class IManor {
tenants: Tenants = new Tenants();

Lazy initialisation of individual array elements

In Swift, lazy properties allow us to only initialise a class member when we ask for it instead of directly at runtime - useful for computationally expensive operations.
I have a class in Swift 4 that is responsible for initialising a strategy from an array of compile-time (developer-hardcoded) provided StrategyProtocol objects. It looks something like this:
class StrategyFactory {
private var availableStrategies: [StrategyProtocol] = [
OneClassThatImplementsStrategyProtocol(),
AnotherThatImplementsStrategyProtocol() // etc
]
public func createStrategy(): StrategyProtocol {
// Depending on some runtime-calculated operation
// How do I do this nicely here?
}
}
However, from my understanding, placing () at the end of each strategy initialises the objects(?), when I may only want to create one depending on certain runtime conditions.
Either way, is it possible to place lazy somewhere around the values in an Array class member to only instantiate the one I want when I ask for it? Or would I have to go about this with closures or some other alternative?
Current attempt
Is this doing what I think it is? Until I get the first element of the array and execute it, it won't actually instantiate the strategy?
private var availableStrategies: [() -> (StrategyProtocol)] = [
{ OneClassThatImplementsStrategyProtocol() }
]
Your "Current attempt" does what you think it does. You have an array
of closures, and the strategy is initialized only when the closure is
executed.
A possible alternative: Store an array of types instead of
instances or closures (as Zalman Stern also suggested).
In order to create instances on demand, a
init() requirement has to be added to the protocol (which must then
be satisfied by a required init() unless the class is final,
compare Why use required Initializers in Swift classes?).
A possible advantage is that you can query static properties
in order to find a suitable strategy.
Here is a small self-contained example, where createStrategy()
creates and returns the first "fantastic" strategy:
protocol StrategyProtocol {
init()
static var isFantastic: Bool { get }
}
class OneClassThatImplementsStrategyProtocol : StrategyProtocol {
required init() { }
static var isFantastic: Bool { return false }
}
final class AnotherThatImplementsStrategyProtocol : StrategyProtocol {
init() { }
static var isFantastic: Bool { return true }
}
class StrategyFactory {
private var availableStrategies: [StrategyProtocol.Type] = [
OneClassThatImplementsStrategyProtocol.self,
AnotherThatImplementsStrategyProtocol.self // etc
]
public func createStrategy() -> StrategyProtocol? {
for strategy in availableStrategies {
if strategy.isFantastic {
return strategy.init()
}
}
return nil
}
}
ANYCLASS, META TYPE AND .SELF may answer your question. (I am not expert on Swift, but use of metaclasses is likely what you want and Swift, as I expected, appears to support them.) You can look through this Stack Overflow search.
EDIT: In case it wasn't clear, the idea is to have the array of strategies contain the metaclasses for the protocols rather than instantiations. Though this depends on whether you want a new strategy object for each instantiation of the class with the lazy property or whether strategies are effectively global and cached ones created. If the latter, then the lazy array approach for holding them might work better.

How to have a generic solution to parse an unknown class to Json in scalaJs

I'm using ScalaJs angular and Upickle and I try to create a filter to transform an unknown class to JSON.
What I tried :
my scope :
var myScope: MyClass = js.native
my filter:
#injectable("copy")
class CopyFilter extends Filter[Any] {
override def filter(any: Any): js.Dynamic = {
val myClass = any.getClass
fromClassToJsValue[myClass](any)
}
}
my function
def fromClassToJsValue[A](value: A)(implicit serializer: Writer[A]): js.Dynamic =
JSON.parse(write(value))
In this case my problem is getClass which returns Class[_] and not MyClass
Is there any solution to find MyClass? (Or maybe any other solution to derive a type Any?)
Broadly speaking, uPickle isn't designed to deal with that; I don't think any of the other JSON serializers are, either. That sort of Any-friendly serialization is usually based on reflection, which mostly isn't available in the JavaScript environment.
I suspect you do need a Filter per case class, albeit probably a one-liner. (Possibly done as a base trait that you mix into the case classes themselves, but I don't know Angular, so I know don't what the constraints look like.)

Creating New Array with Class Object in GWT

I would like to create a new array with a given type from a class object in GWT.
What I mean is I would like to emulate the functionality of
java.lang.reflect.Array.newInstance(Class<?> componentClass, int size)
The reason I need this to occur is that I have a library which occasionally needs to do the following:
Class<?> cls = array.getClass();
Class<?> cmp = cls.getComponentType();
This works if I pass it an array class normally, but I can't dynamically create a new array from some arbitrary component type.
I am well aware of GWT's lack of reflection; I understand this. However, this seems feasible even given GWT's limited reflection. The reason I believe this is that in the implementation, there exists an inaccessible static method for creating a class object for an array.
Similarly, I understand the array methods to just be type-safe wrappers around JavaScript arrays, and so should be easily hackable, even if JSNI is required.
In reality, the more important thing would be getting the class object, I can work around not being able to make new arrays.
If you are cool with creating a seed array of the correct type, you can use jsni along with some knowledge of super-super-source to create arrays WITHOUT copying through ArrayList (I avoid java.util overhead like the plague):
public static native <T> T[] newArray(T[] seed, int length)
/*-{
return #com.google.gwt.lang.Array::createFrom([Ljava/lang/Object;I)(seed, length);
}-*/;
Where seed is a zero-length array of the correct type you want, and length is the length you want (although, in production mode, arrays don't really have upper bounds, it makes the [].length field work correctly).
The com.google.gwt.lang package is a set of core utilities used in the compiler for base emulation, and can be found in gwt-dev!com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang.
You can only use these classes through jsni calls, and only in production gwt code (use if GWT.isProdMode()). In general, if you only access the com.google.gwt.lang classes in super-source code, you are guaranteed to never leak references to classes that only exist in compiled javascript.
if (GWT.isProdMode()){
return newArray(seed, length);
}else{
return Array.newInstance(seed.getComponentType(), length);
}
Note, you'll probably need to super-source the java.lang.reflect.Array class to avoid gwt compiler error, which suggests you'll want to put your native helper method there. However, I can't help you more than this, as it would overstep the bounds of my work contract.
The way that I did a similar thing was to pass an empty, 0 length array to the constructor of the object that will want to create the array from.
public class Foo extends Bar<Baz> {
public Foo()
{
super(new Baz[0]);
}
...
}
Baz:
public abstract class Baz<T>
{
private T[] emptyArray;
public Baz(T[] emptyArray)
{
this.emptyArray = emptyArray;
}
...
}
In this case the Bar class can't directly create new T[10], but we can do this:
ArrayList<T> al = new ArrayList<T>();
// add the items you want etc
T[] theArray = al.toArray(emptyArray);
And you get your array in a typesafe way (otherwise in your call super(new Baz[0]); will cause a compiler error).
I had to do something similar, I found it was possible using the Guava library's ObjectArrays class. Instead of the class object it requires a reference to an existing array.
T[] newArray = ObjectArrays.newArray(oldArray, oldArray.length);
For implementing an array concatenation method, I also stepped into the issue of missing Array.newInstance-method.
It's still not implemented, but if you have an existing array you can use
Arrays.copyOf(T[] original, int newLength)
instead.

Resources