Swift: Define relationships between classes - swift

I'm trying to figure out how to setup the relationship between two classes so that I'm able to determine the properties of one by knowing the other.
Let's say I have Owner and Pet, where the owner has a pet.
class Owner{
let name: String
var age: Int
let petName: String
init(name: String, age: Int, petName: String) {
self.name = name
self.age = age
self.petName = petName
}
}
class Pet{
let petName: String
var age: Int
let petType: String
init(petName: String, age: Int, petType: String) {
self.petName = petName
self.age = age
self.petType = petType
}
}
Assuming each petName is unique, I'd like to be able to do something like owner.petType where I can return the petType for the petName of the owner. Is this possible? Should I set the classes up differently?

You can set up your classes as such:
class Owner {
let name: String
var age: Int
var pet: Pet? //Owner might not have a pet - thus optional or can also have an array of pets
init(name: String, age: Int, pet: Pet) {
self.name = name
self.age = age
self.pet = pet
}
}
class Pet {
let name: String
var age: Int
let type: String
init(name: String, age: Int, type: String) {
self.name = name
self.age = age
self.type = type
}
}

Related

Scala help. DynamoDBMappingException: could not unconvert attribute

I defined the following table in Scala. When I ran a test to query data from the dynamodb table, it throws exceptions:
com.amazonaws.services.dynamodbv2.datamodeling.
DynamoDBMappingException
: TsuIntersectionRecord[comments]; could not unconvert attribute
The problem is with comments attribute, which is a list (SS). What should I do to fix unconert problem?
#DynamoDBTable(tableName = "tsu-overrides-table")
case class TsuIntersectionRecord(
#(DynamoDBHashKey #beanGetter)(attributeName = "overrideId")
#BeanProperty
var overrideId: String,
#(DynamoDBRangeKey #beanGetter)(attributeName = "intersection")
#BeanProperty
var intersection: String,
#(DynamoDBAttribute #beanGetter)(attributeName = "runId")
#BeanProperty
var runId: String,
#(DynamoDBAttribute #beanGetter)(attributeName = "snapshotDate")
#BeanProperty
var snapshotDate: String,
#(DynamoDBAttribute #beanGetter)(attributeName = "tsuValue")
#BeanProperty
var tsuValue: Double,
#(DynamoDBAttribute #beanGetter)(attributeName = "action")
#BeanProperty
var action: String,
#(DynamoDBAttribute #beanGetter)(attributeName = "overrideValue")
#BeanProperty
var overrideValue: Option[Double],
#(DynamoDBAttribute #beanGetter)(attributeName = "comments")
#BeanProperty
var comments: List[String],
#(DynamoDBAttribute #beanGetter)(attributeName = "lastUpdateTime")
#BeanProperty
var lastUpdateTime: Int
) {
def this() = this(null, null, null, null, 0.0, null, None, List(), 0)
}

Arguments in Auxiliary Constructor in Scala

I am trying to create 2 auxiliary constructors .But not able to do so.
class learnMultipleAuxuliaryConstructor(firstname: String,
lastName: String,
middleName: String) {
println("This is primary constructor")
println("Complete Name is " + firstname + lastName + middleName)
def this(firstname: String) {
this(firstname, "", "")
println("This is Auxiliary constructor with firstname")
println("First Name is " + firstname)
}
def this(lastname: String) {
this("", lastname, "")
println("This is Auxiliary constructor with lastname")
println("lastname is " + lastname)
}
}
Can i do this?
You have to have distinct constructor signatures. So:
class learnMultipleAuxuliaryConstructor(firstname: String,
lastName: String,
middleName: String) {
def this(firstname: String) ...
def this(lastname: String) ...
}
is not possible. For such case it would be better to have either default parameters and named parameters:
class learnMultipleAuxuliaryConstructor(firstname: String = "",
lastName: String = "",
middleName: String = "")
new learnMultipleAuxuliaryConstructor(lastName = "Custom")
or separate methods in companion objects with distinct names:
object learnMultipleAuxuliaryConstructor {
def fromFirstName(firstName: String) = ...
def fromLastName(lastName: String) = ...
}

Scala: Convert nearly identical case classes with value of different type

Say I have a case class of:
case class car1 (
var wheels: Map[String, String] = Map[String, String](),
var tire: String = "",
var window: String = ""
) {}
and I simply want to convert an instance of it into another case class with a single difference in the type of one variable wheels, with all other values the same:
case class car2 (
var wheels: Array[(String, String)],
var tire: String = "",
var window: String = ""
) {}
What is the best way in Scala to:
1. Abstract all boilerplate default values into a single structure
2. convert between the two classes such that a conversion changes the type of the wheels value
I want to convert an instance of car1 into car2 such that a standard conversion function is applied to wheels.
I would add an apply function in the companion object of car2:
object car2 {
def apply(car1: car1): car2 =
car2(car1.wheels.toArray, car1.tire, car1.window)
}
Usage:
car2(car1(Map("x" -> "a"), "conti", "glass"))
2. Try
case class car1 (
var wheels: Map[String, String] = Map[String, String](),
var tire : String = "",
var window: String = ""
) {
def toCar2: car2 = car2(wheels.toArray, tire, window)
}
1. Try
def default[A](implicit factory: Factory[_, A]): A = factory.newBuilder.result()
case class car1 (
var wheels: Map[String, String] = default,
var tire : String = default,
var window: String = default
) {
def toCar2: car2 = car2(wheels.toArray, tire, window)
}
case class car2 (
var wheels: Array[(String, String)] = default,
var tire : String = default,
var window: String = default
) {}
Scala 2.13.

Non-value field is accessed in 'hashCode()'

It happen with id. (Non-value field is accessed in 'hashCode()')
How can I fix it?
Here is my code:
import java.util.Date
case class Category() {
var id: Integer = _
var parentId: Integer = _
var name: String = _
var status: Boolean = _
var sortOrder: Integer = _
var createTime: Date = _
var updateTime: Date = _
def this(id: Integer, parentId: Integer, name: String, status: Boolean, sortOrder: Integer, createTime: Date, updateTime: Date) {
this()
this.id = id
this.parentId = parentId
this.name = name
this.status = status
this.sortOrder = sortOrder
this.createTime = createTime
this.updateTime = updateTime
}
override def hashCode(): Int = {
if (id != null) id.hashCode() else 0
}
}
If I change var id to val id, it will be ok. But I need setter, I cant't set it as a val.
Non value field in hashCode means you're relaying on a mutable field to generate the classes hashcode, which may be dangerous, depending how you use that class. For example, assume you have a HashMap[Category, String], you place an entry in the hash map and them mutate the id field, now that hashmap can no longer find the class instance by it's hashcode.
You're treating a case class like it's a regular, mutable Java class. Case classes provides the mechanism of encapsulating immutable data in a syntax convenient way (where you also get a few nice things for free, such as hashCode, equals, etc). What you can do is make your case class accept parameters via it's primary constructor:
case class Category(id: Int,
parentId: Int,
name: String,
status: Boolean,
sortOrder: Int,
createTime: Date,
updateTime: Date) {
override def hashCode(): Int = id.hashCode()
}
If you want to update Category, you can use the utility copy method defined on a case class:
val cat = Category(id = 1,
parentId = 1,
name = "Hello",
status = true,
sortOrder = 1,
createTime = new Date(123132123L),
updateTime = new Date(52234234L))
val newCat: Category = cat.copy(id = 2)
Another way of approaching this (which I like less TBH) would be to make all your fields an Option[T] with a default value set to None:
case class Category(id: Option[Int] = None,
parentId: Option[Int] = None,
name: Option[String] = None,
status: Option[Boolean] = None,
sortOrder: Option[Int] = None,
createTime: Option[Date] = None,
updateTime: Option[Date] = None) {
override def hashCode(): Int = id.map(_.hashCode()).getOrElse(0)
}
And then updating them once you can populate the class with data:
val cat = Category()
val newCat = cat.copy(id = Some(1))
After I try many times, I think this should be a good choice.
Any ideas?
override def hashCode(): Int = {
if (getId != null) getId.hashCode() else 0
}

How do I make a parameter default to the value of another parameter in Scala?

Why can't I do the following:
def multiply(a: Int, b: Int = a) = a * b
or
case class Point(x: Int, y: Int = x)
Is there another way to achieve the same? The reason I need this is because sometimes, the arguments having different values is more the exception than the rule. Take for example:
case class User(name: String, age: String, description: String, displayName: String = name, online: Boolean = false)
In 90% of the cases, display name and name should be the same, but in a few edge cases, it should not. Having one parameter default to the value of another would be very useuful. Is there a way to do this? And if not, why?
Yes. Parameters in a parameter list can refer to argument values in previous parameter lists, similar to how type inference can refer to types in previous parameter lists:
def multiply(a: Int)(b: Int = a) = a * b
case class Point(x: Int)(y: Int = x)
case class User(name: String, age: String, description: String)(displayName: String = name, online: Boolean = false)
should work.
One way can be to define case class as
case class User(name: String, age: String, description: String, displayName: String, online: Boolean = false) {
def this(name: String, age: String, description: String, online: Boolean = true) =
this(name, age, description, name, online)
}
Then you can create case class as
val user = new User("User name", "5", "description")
//> user : User = User(User name,5,description,User name,true)
user.displayName
//> res0: String = User name
val userWithDisplayName = new User("User name", "5", "description", "displayName")
//> userWithDisplayName : User = User(User name,5,description,displayName,false)
You can also override apply method in the companion object. That way you will not have to write new before creating the object
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class User(name: String, age: String, description: String, displayName: String, online: Boolean = false)
object User {
def apply(name: String, age: String, description: String, online: Boolean) =
new User(name, age, description, name, online)
}
// Exiting paste mode, now interpreting.
defined class User
defined module User
scala> User("User name", "5", "description", "displayName")
res0: User = User(User name,5,description,displayName,false)
scala> User("User name", "5", "description", true)
res1: User = User(User name,5,description,User name,true)