Is this an anti-pattern/code smell? - Using enum/class of consts to access class properties with [] instead of using dot property - properties

class FruitFields {
static const NAME = "name";
static const DESCRIPTION = "descriptionText";
}
class Fruit {
final string name;
final string descriptionText;
Fruit(required string id, required string descriptionText);
}
Then when I want to do something with a Fruit use the [] instead of . notation.
var banana = new Fruit('banana', 'a yellow fruit')
banana[FruitFields.DESCRIPTION] = 'a very yellow fruit'
// instead of
banana.descriptionText = 'a very yellow fruit'
Why? So I can refactor without having to think. If I want to change DESCRIPTION to SUMMARY it's easier to do a find and replace on FruitFields.DESCRIPTION verse apple.descriptionText, banana.descriptionText... where some non fruit object like car.descriptiontText could have a similarly named property I would have to watch out for.
I can't tell if this dumb or not.

The compiler can't help you to spot a typo in the value if you use strings. Using enums however, the compiler only let you use valid values. You also get an performance benefit. An enum value is just a number and it's faster to work with numbers than with strings.

Related

Arrow lens won't let me set a nullable property to null

Given this (extremely simplified) code :
#optics
data class MigrationStatus(val token: String?)
val m = MigrationStatus(null)
I can call
val m1 = MigrationStatus.token.modify(m) { "some token" }
But as the argument type is a non nullable String, how can I modify token back to null ? Of course
val m2 = MigrationStatus.token.modify(m1) { null }
does not compile.
The same happens when changing token type to an Option<String> when trying to set it to None, but I avoided it as it is now deprecated (which I'm not sure I like, but that's another matter).
Did I miss something obvious ?
The #Optics compiler generates 2 optics for that property.
MigrationStatus.token & MigrationStatus.tokenNullable or MigrationStatus.tokenOption in the case of Option.
This is because there are two different Optics that are useful here.
Lens which has set & get and in this case `Lens<MigrationStatus, String?>
Optional which has set & getOption and in this case `Optional<MigrationStatus, String>
The first one is the one you'd want to use in this case to be able to set String? to null.
So MigrationStatus.tokenNullable.set(null).
The latter is more useful for the DSL, and composition of Optics since if instead of String? you had another data class or sealed class you'd want to operate on the value only in the case of not-null.
I hope that fully answers your question!

Kotlin multiple class for data storage

I am developing a simple Android app, that will display an icon of a vehicle and the user can click on the icon to display the vehicle information. I want to load the data dynamically when I build the app i.e. the data will come from an external source including the picture for the icon.
I am new to Kotlin and not sure what to search for to understand a suitable solution. What is the correct way to define the data, is it best to create an class as below then create an array of the class (not sure if this is possible)
public class VehicleSpec()
{
var OEM: String? = null
var ModelName: String? = null
var EngineSize: String? = null
}
Or would be better to create a multiple dimension array and then link the data to the cells?
var VehicleSpec = arrayOf(20,20)
VehicleSpec[0][0] = Null //OEM
VehicleSpec[0][1] = Null //ModelName
VehicleSpec[0][2] = Null //EngineSize
What is the best way to set up the data storage, is there any good references to understand how this should be setup?
What is the correct way to define the data, is it best to create an class as below then create an array of the class
Using an array for the properties of an object is not making the full use of the type safety you have in Kotlin (and even Java for that matter).
If what you want to express is multiple properties of an object, then you should use a class to define those properties. This is especially true if the properties have different types.
There is no performance difference between an array and a class, because you'll get a reference to the heap in both cases. You could save on performance only if you convert your multi-dimensional array approach to a single-dimension array with smart indexing. Most of the time, you should not consider this option unless you are handling a lot of data and if you know that performance is an issue at this specific level.
(not sure if this is possible)
Defining lists/arrays of classes is definitely possible.
Usually, for classes that are only used as data containers, you should prefer data classes, because they give you useful methods for free, and these methods totally make sense for simple "data bags" like in your case (equals, hashcode, component access, etc.).
data class Vehicle(
val OEM: String,
val ModelName: String,
val EngineSize: String
)
Also, I suggest using val instead of var as much as possible. Immutability is more idiomatic in Kotlin.
Last but not least, prefer non-null values to null values if you know a value must always be present. If there are valid cases where the value is absent, you should use null instead of a placeholder value like empty string or -1.
First at all, using the "class aprocah" makes it easy for you to understand and give you the full benefits of the language itself... so dont dry to save data in an array .. let the compiler handle those stuff.
Secondly i suggest you have maybe two types (and use data classes ;-) )
data class VehicleListEntry(
val id: Long,
val name: String
)
and
data class VehicleSpec(
val id: Long,
val oem: String = "",
val modelName: String = "",
val engineSize: String = ""
)
from my perspective try to avoid null values whenever possible.
So if you have strings - which you are display only - use empty strings instead of null.
and now have a Model to store your data
class VehicleModel() {
private val specs: MutableMap<Long, VehicleSpec> = mutableMapOf()
private var entries: List<VehicleListEntry> = listOf()
fun getSpec(id: Long) = specs[id]
fun addSpec(spec: VehicleSpec) = specs[spec.id] = spec
fun getEntries(): List<VehicleListEntry> = entries
fun setEntries(data: List<VehicleListEntry>) {
entries = data.toMutableList()
}
}
You could also use a data class for your model which looks like
data class VehicleModel(
val specs: MutableMap<Long, VehicleSpec> = mutableMapOf(),
var entries: List<VehicleListEntry> = listOf()
)
And last but not least a controller for getting stuff together
class VehicleController() {
private val model = VehicleModel()
init{
// TODO get the entries list together
}
fun getEntries() = model.entries
fun getSpec(id: Long) : VehicleSpec? {
// TODO load the data from external source (or check the model first)
// TODO store the data into the model
// TODO return result
}
}

Should Constructor Parameter Names be Abbreviations of Instance Variables?

For example, with this class,
class Dog {
String name;
int colour;
}
would it better to have a constructor with parameters that have the same name as the instance variables they represent, like this:
public Dog(String name, int colour) {
this.name = name;
this.colour = colour;
}
Or is it better to abbreviate the names of the parameters, like this:
public Dog(String n, int col) {
name = n;
colour = col;
}
It’s better to use the full field name for parameters, because it’s clearer.
Even though it take’s slightly more code (adding this.), clarity wins.
Also, it avoids the problem of naming convention when two fields share the same first letter.

Is there an equivalent to Fortran's select type statement in Chapel?

I'd like to try out classes and polymorphism in Chapel, so I am trying to
get the following example code to work:
module SomeAnimals {
class Animal {
}
class Bird: Animal {
}
class Fish: Animal {
}
proc Bird.fly() {
writeln("Flying ...!");
}
proc Fish.swim() {
writeln("Swimming ...!");
}
} // module SomeAnimals
proc main() {
use SomeAnimals;
var anim: Animal;
anim = new Fish();
select (anim.type) {
when Fish do anim.swim();
}
delete anim;
anim = new Bird();
select (anim.type) {
when Bird do anim.fly();
}
delete anim;
} // proc main
This compiles, but upon running it, it simply exits without producing any
print-out. Apparently, the calls to the anim.swim() and anim.fly() methods, contained within the select statements, aren't executed for some reason. Without making use of these select statements to check the actual type of the polymorphic variable "anim", the code, of course, doesn't compile.
The above example is actually a rather literal translation of a working
Fortran 2008 code that makes use of Fortran's "select type" statement. Does
Chapel provide a similar statement, or does this example have to be coded in a completely different fashion in order to work in Chapel? I couldn't find anything of relevance in the Chapel documentation.
The key for understanding why your code isn't working is that myVar.type in Chapel refers to the variable's static type rather than its dynamic type. So even though you and I can see that anim is a Fish initially and a Bird later, anim.type will always be Animal since it was declared as var anim: Animal; giving it the static type Animal. You can see this by changing your main() function to the following (try it online):
proc main() {
use SomeAnimals;
var anim: Animal;
anim = new Fish();
writeln(anim.type:string);
anim = new Bird();
writeln(anim.type:string);
} // proc main
where the output will be:
Animal
Animal
One way to reason about a class variable's dynamic type in Chapel is to apply the cast operator (:) to it, which behaves similarly to dynamic casts in C++. Namely, if I try to cast a variable whose static type is Animal to Fish but it's really a Bird, I'll get nil back, indicating that the class object was neither a Fish nor a subclass of Fish.
So a rewrite of your main() that behaves as you'd like would be the following (try it online):
proc main() {
use SomeAnimals;
var anim: Animal = new Fish();
var aFish = anim:Fish;
if aFish then
aFish.swim();
delete anim;
anim = new Bird();
var aBird = anim:Bird;
if aBird then
aBird.fly();
delete anim;
} // proc main
(where I'm using the shorthand if classVar ... for if classVar != nil ...)
Rewinding to your specific question about whether Chapel has a Fortran-like type select statement, it does not at present. For reasoning about static types (like int vs. real vs. my record R vs. a subclass of C), using the select statement on a variable's type as you did is completely reasonable (or you could provide overloads of a function where we'd choose the correct one based on the argument's static type). But for cases where you're working within a class hierarchy and have to reason about the dynamic type of the object, your main tools will be casting, as above, or dynamic dispatch, or storing an explicit field in the class to distinguish between the cases (which can be thought of as a manual implementation of the dynamic cast).

Iterate enum values using values() and valueOf in kotlin

Am a newbie here. Can anyone give an example to iterate an enum with values and valueOf methods??
This is my enum class
enum class Gender {
Female,
Male
}
I know we can get the value like this
Gender.Female
But I want to iterate and display all the values of Gender. How can we achieve this? Anyhelp could be appreciated
You can use values like so:
val genders = Gender.values()
Since Kotlin 1.1 there are also helper methods available:
val genders = enumValues<Gender>()
With the above you can easily iterate over all values:
enumValues<Gender>().forEach { println(it.name) }
To map enum name to enum value use valueOf/enumValueOf like so:
val male = Gender.valueOf("Male")
val female = enumValueOf<Gender>("Female")
You're getting [LGender;#2f0e140b or similar as the output of printing Gender.values() because you're printing the array reference itself, and arrays don't have a nice default toString implementation like lists do.
The easiest way to print all values is to iterate over that array, like this:
Gender.values().forEach { println(it) }
Or if you like method references:
Gender.values().forEach(::println)
You could also use joinToString from the standard library to display all values in a single, formatted string (it even has options for prefix, postfix, separator, etc):
println(Gender.values().joinToString()) // Female, Male
You can add this method to your enum class.
fun getList(): List<String> {
return values().map {
it.toString()
}
}
And call
val genders = Gender.getList()
// genders is now a List of string
// Female, Male
You can do this and get a new array of your enum type Gender
val arr = enumValues<Gender>()
and if you want a list of its, you can use the extension. toList()