I'm used to being able to in Java define an object which can contain other objects as members, for example (psuedocode):
class Zoo{
private List<Animal> animals;
}
class Animal {
private double weight;
private double height;
private double species;
}
Then you could have a constructor for zoo which takes X animals and adds them to an animal collection and have it's own methods.
In coffeescript I can't seem to be able to do this, is this a limitation of javascript?
hope I understood your question.
in Coffeescript you may write
class Animal
name: ''
class Zoo
animals: [] #notice you do not specify type!
constructor: (animalList) ->
#animals = animalList #and animal list is an array of Animal class instances
zoo = new Zoo([new Animal()])
console.log(zoo.animals.length) #should be eq to 1
If you want animals to be private same as it would be in Java or C#, I would recommend not using classes but:
Zoo = (animals) ->
return {
getAnimals: -> animals
addToAnimals: (animal) -> animals.push(animal)
}
Related
I have an interface which defines a method. I have a struct which implements this interface. In it, I have implemented the methods from this interface and also have additional methods defined.
For example:
package main
import (
"fmt"
)
type Animal interface {
MakeNoise()
}
type Dog struct {
color string
}
/* Interface implementation */
func (d *Dog) MakeNoise() {
fmt.Println("Bark!")
}
/* End Interface implementation */
func (d *Dog) WagTail() {
fmt.Println(d.color + " dog: Wag wag")
}
func NewDog(color string) Animal {
return &Dog{color}
}
func main() {
dog := NewDog("Brown")
dog.MakeNoise()
dog.WagTail()
}
On Playground: https://play.golang.org/p/B1GgoNToNl_l
Here, WagTail() is not part of the Animal interface but belongs to the Dog struct. Running this code gives an error
dog.WagTail undefined (type Animal has no field or method WagTail).
Is there a way I could have a struct adhere to an interface and also define it's own methods?
This may help you.
d := dog.(*Dog)
d.WagTail()
On Playground: https://play.golang.org/p/KlNqpmvFTJi
The error described it all:
dog.WagTail undefined (type Animal has no field or method WagTail)
To implement an interface you should implement all methods defined inside it.
dog := NewDog("Brown")
dog.MakeNoise()
dog.WagTail()
Now NewDog returns Animal interface which contains MakeNoise method but not WagTail.
The only way to manage your requirement is either create a variable of struct type Dog and then you can call any method having Dog as receiver.
d := &Dog{"Brown"}
d.WagTail()
Or you can return the pointer to Dog struct from NewDog method just like you did in your code mentioned in the comment as:
func NewDog(color string) *Dog {
return &Dog{color}
}
But if the method is not defined in interface you cannot implement it using the struct as method receiver.
Golang provides a way in which:
You can ask the compiler to check that the type T implements the
interface I by attempting an assignment using the zero value for T or
pointer to T, as appropriate
type T struct{}
var _ I = T{} // Verify that T implements I.
var _ I = (*T)(nil) // Verify that *T implements I.
If T (or *T, accordingly) doesn't implement I, the mistake will be caught at compile time.
If you wish the users of an interface to explicitly declare that they
implement it, you can add a method with a descriptive name to the
interface's method set. For example:
type Fooer interface {
Foo()
ImplementsFooer()
}
A type must then implement the ImplementsFooer method to be a Fooer, clearly documenting the fact and announcing it in godoc's output.
type Bar struct{}
func (b Bar) ImplementsFooer() {}
func (b Bar) Foo() {}
Most code doesn't make use of such constraints, since they limit the
utility of the interface idea. Sometimes, though, they're necessary to
resolve ambiguities among similar interfaces.
You can definitely do it, one such method is using type assertion as shown in the other answer here. Otherwise the answer by #Himanshu here describes the situation very well.
I would like to add to the discussion to further describe how you
could have a struct adhere to an interface and also define it's own methods
The MakeDog method returns an Animal, and there are a number of reasons you may consider returning a Dog (or whichever concrete type) directly.
The reason I bring this up is because of something someone told me about creating methods when I first started programming in Go:
Accept an Interface and return a Concrete type (such as a Struct)
Interfaces can accept any concrete type. That's why they are used when you don't know the type of argument you are passing to the function.
I did a google search with the following terms and quite a few articles turned up
golang accept interface, return struct
For example: https://mycodesmells.com/post/accept-interfaces-return-struct-in-go and http://idiomaticgo.com/post/best-practice/accept-interfaces-return-structs/
I have put together a little bit of a demo extending on your concepts in your question to try and clearly describe interface methods as well as methods and attributes for specific types
Taken from this snippet on Playground
package main
import (
"fmt"
)
type Animal interface {
MakeNoise() string
}
// printNoise accepts any animal and prints it's noise
func printNoise(a Animal) {
fmt.Println(a.MakeNoise())
}
type pet struct {
nLegs int
color string
}
// describe is available to all types of Pet, but not for an animal
func (p pet) describe() string {
return fmt.Sprintf(`My colour is "%s", and I have "%d" legs`, p.color, p.nLegs)
}
type Dog struct {
pet
favouriteToy string
}
// MakeNoise implements the Animal interface for type Dog
func (Dog) MakeNoise() string {
return "Bark!"
}
// WagTail is something only a Dog can do
func (d Dog) WagTail() {
fmt.Println("I am a dog,", d.pet.describe(), ": Wags Tail")
}
type Cat struct {
pet
favouriteSleepingPlace string
}
// MakeNoise implements the Animal interface for type Cat
func (Cat) MakeNoise() string {
return "Meow!"
}
// ArchBack is something only a Cat can do
func (c Cat) ArchBack() {
fmt.Println("I am a cat,", c.pet.describe(), ": Arches Back")
}
type Bird struct {
pet
favoritePerch string
}
// MakeNoise implements the Animal interface for type Cat
func (Bird) MakeNoise() string {
return "Tweet!"
}
// Hop is something only a Bird can do
func (c Bird) Hop() {
fmt.Println("I am a bird,", c.pet.describe(), ": Hops to a different perch")
}
func main() {
dog := Dog{
pet: pet{nLegs: 4, color: "Brown"},
favouriteToy: "Ball",
}
printNoise(dog)
dog.WagTail()
cat := Cat{
pet: pet{nLegs: 4, color: "Tabby"},
favouriteSleepingPlace: "Sofa",
}
printNoise(cat)
cat.ArchBack()
bird := Bird{
pet: pet{nLegs: 2, color: "Rainbow"},
favoritePerch: "Back of Cage",
}
printNoise(bird)
bird.Hop()
}
Yes, you can run methods that are not part of the interface. There were two issues in the code preventing it from running properly.
The function NewDog returns the type Animal. The WagTale method is attached to Dog not Animal which gave an error. The return type has been changed to Dog.
Pointers are not needed in this code and have been removed.
After these adjustments, the code runs and properly and all methods execute as expected.
Link on Go playground: https://play.golang.org/p/LYZJiQND7WW
package main
import (
"fmt"
)
type Animal interface {
MakeNoise()
}
type Dog struct {
color string
}
/* Interface implementation */
func (d Dog) MakeNoise() {
fmt.Println("Bark!")
}
/* End Interface implementation */
func (d Dog) WagTail() {
fmt.Println(d.color + " dog: Wag wag")
}
func NewDog(color string) Dog {
return Dog{color}
}
func main() {
dog := NewDog("Brown")
dog.MakeNoise()
dog.WagTail()
}
Here is the problem I am trying to resolve, I am trying to use a void type as a generic type:
class Parent {
private abstract class Item<out T>(val data: T)
// This subclass should contain data
private class ItemContent(val data: String): Item<String>(data)
// This subclass doesn't contain data
private class ItemNoContent: Item<Any?>(null)
}
Some base classes like ItemNoContent doesn't contain meaningful data so I make ItemNoContent extends Item(null). It works but I feel that the use of Any? and null is inappropriate here. Is there a more Kotlin way to solve this optional generic problem?
You can also use Item<Unit>(Unit) which represents a void value in Kotlin.
Some base classes like ItemNoContent doesn't contain meaningful data
Then why extend a class which is supposed to have it? While Unit and null are both options, consider also
private abstract class Item<out T>
private abstract class ItemWithContent<out T>(val data: T) : Item<T>
...
// object may make more sense than class here
private object ItemNoContent : Item<Nothing>()
I would tweak the inheritance like this:
abstract class Item
abstract class ItemWithContent<T>(val d: T): Item()
class ItemWithStringContent(d: String): ItemWithContent<String>(d)
class ItemWithNoContent: Item()
This way, there is not need to use Unit or Nothing.
Usage:
fun main(args: Array<String>){
val t: Item = ItemWithStringContent("test")
println((t as? ItemWithStringContent)?.d)
}
I tried to resolve task #6 (DataClass) at Kotlin Koans. When I used the normal class in code, the test case failed.
Here's my code of the data class:
data class Person(val name: String, val age: Int)
fun task6(): List<Person> {
return listOf(Person("Alice", 29), Person("Bob", 31))
}
Here's result of the data class:
[Person(name=Alice, age=29), Person(name=Bob, age=31)]
Here's my code of the normal class:
class Person(val name: String, val age: Int)
fun task6(): List<Person> {
return listOf(Person("Alice", 29), Person("Bob", 31))
}
Here's result of the normal class:
[i_introduction._6_Data_Classes.Person#4f47d241, i_introduction._6_Data_Classes.Person#4c3e4790]
Does that mean there is difference between a normal class and a data class in Kotlin. If yes, what is that?
Updated:
Thank #Mallow, you are right. That works:
class Person(val name: String, val age: Int) {
override fun toString(): String {
return "Person(name=$name, age=$age)"
}
}
fun task6(): List<Person> {
return listOf(Person("Alice", 29), Person("Bob", 31))
}
Most of the time we developers use class to keep only data in classes. Classes have some methods which needs to be overridden wrt the data it holds. ex: hashCode(), equals().
Data classes automatically take care of such utilities.
From the official documentation:
We frequently create a class to do nothing but hold data. In such a class some standard functionality is often mechanically derivable from the data. In Kotlin, this is called a data class and is marked as data.
The compiler automatically derives the following members from all properties declared in the primary constructor:
equals()/hashCode() pair,
toString() of the form "User(name=John, age=42)",
componentN() functions corresponding to the properties in their order of declaration,
copy() function (see below).
If any of these functions is explicitly defined in the class body or inherited from the base types, it will not be generated.
To read more, check data-classes
About the result, Technically, you are getting is different because of implementation of toString() method. data class' toString() method uses data class properties and values to form returning string. General class' toString() method uses hash code to form returning string.
for a data class.
The compiler automatically derives the following members from all
properties declared in the primary constructor:
equals()/hashCode() pair,
toString() of the form "User(name=John, age=42)",
componentN() functions corresponding to the properties in their order
of declaration,
copy() function (see below).
see https://kotlinlang.org/docs/reference/data-classes.html
A class represents some data "type" and its behaviour(s) so from that point of view data class isn't any different than a class. But there are certain behaviours and rules about a data class that makes it a bit different:
Calling toString() on a data class dumps a string with all its member properties.
It has componentN method that get member properties by their order n.
It has a copy method which takes the member properties as parameters for making a diff copy of the object.
A data class can not be open. Cant be inherited.
It can not be abstract.
It can not be nested, inner or sealed.
Although it can inherit, define abstract methods and implement interfaces.
data class properties can be destructed into individual variables e.g val (name, address) = Person("name", "address")
Pair(a, b) internally uses data class.
It is very common to create classes whose main goal is to hold data. If you want your class to be a convenient holder for your data you need to override the universal object methods:
toString() - string representation
equals() - object equality
hashCode() - hash containers
Note: equals() is used for structural equality and it is often implemented among with hashCode().
Usually, the implementation of these methods is straightforward, and your IDE can help you to generate them automatically. However, in Kotlin, you don't have to general all of these boilerplate code. If you add the modifier data to your class, the necessary methods are automatically added for you.
The return value of toString() will have the format ClassName(parm1=value1, param2=value2, ...). equals() and hashCode() methods take into account all the properties declared in the primary constructor.
The copy() method
When you mark a class as a data class, the method copy() is also automatically generated which allows you to make copies of an existing instance. This feature is very handy when you are using your instances as keys for a HashMap or if you are dealing with multithreaded code.
Even though the properties of a data class are not required to be val, i.e., you can use var, it is strongly recommended that you use read-only properties, so that you make the instances immutable.
Finally, componentN() functions corresponding to the properties in their order of declaration are also generated by the compiler when you mark a class as a data class.
Sample Code
class PersonClass(val name: String, val age: Int)
data class PersonDataClass(val name: String, val age: Int)
>>> val ron = PersonClass("Ron", 18)
>>> val harry = PersonDataClass("Harry", 17)
>>> println(ron) // notice the string representation of a regular class
PersonClass#3b6eb2ec
>>> println(harry) // notice the string representation of a data class
PersonDataClass(name=Harry, age=17)
>>> val harryClone = harry.copy() // this creates a copy of the object referenced by harry
>>> val hermione = PersonDataClass("Hermine", 16)
>>> harry == harryClone
true
>>> harry == hermione
false
In summary, if you need a holder for data, you should use a data class which means adding the modifier data to your class. This will generate the following methods for you: toString(), equals(), hashCode(), componentN(), and copy(), so you avoid writing boilerplate code. If you use a regular class, you won't have all these "batteries included".
Data Class contains internal code which we have to override in Java-like Kotlin generates the equals(), hashCode(), and toString()
Kotlin:
data class User(val name: String, val age: String)
Java:
class Student {
public final String name;
public final String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
#Override
public boolean equals(Object other) {
}
#Override
public long hashCode() {
}
#Override
public String toString() {
return "User(name=" + name + ",age=" + age + ")";
}
}
Normal Class:
Can be abstract, open, sealed, or inner but not for Data Class
Constructor parameter can be declared without var and val
I have a type like this
sealed class Foo[A](val value: A)
object Foo {
def apply[A](v: A)(implicit num: Numeric[A]): Foo[A] =
/* highly complex stuff to make a Foo[A] */
implicit def toA[A](x: Foo[A]) = x.value
}
Foo as a class is only supposed to hold the value, so an implicit Numeric would not make much sense. But I need the type of A to be always a numeric.
So my idea is to just make it impossible to use Foos normal constructor outside of its companion. Is that possible in Scala?
Yeah, since the companion object can access private members of its companion class you can just make the primary (and auxiliary if any) constructor private.
Pseudo code here:
class ConcreteFoo private (n: Int) extends Foo(n)
I'm working on a homework assignment for my object oriented design class, and I'm running into trouble with Scala's companion objects. I've read in a few places that companion objects are supposed to have access to their companion class's private methods, but I can't seem to get it to work. (Just as a note, the meat of the assignment had to do with implementing a binary search tree, so I'm not just asking for answers...)
I have an object that is supposed to create an instance of my private class, BstAtlas (Bst is also defined in the Atlas object, took it out for clarity):
object Atlas {
def focusRoom(newRoom:Room,a:Atlas):Atlas = a.helpFocusRoom(newRoom);
abstract class Atlas {
...
protected def helpFocusRoom(n:Room):Atlas;
...
}
private class BstAtlas(bst:Bst) extends Atlas {
...
protected def helpFocusRoom(newRoom:Room):Atlas = ...
// uses some of bst's methods
...
}
}
But when I go to compile, I get the following error:
Question23.scala:15: error: method
helpFocusRoom cannot be accessed in
Atlas.Atlas
a.helpFocusRoom(newRoom);
The function helpFocusRoom needs to be hidden, but I don't know how to hide it and still have access to it inside of the companion object.
Can anyone tell me what I'm doing wrong here?
The problem is that classes and companion objects can't be nested like that. To define a companion object, you need to define the class outside of the object's body but in the same file.
Companion objects should be next to their real object, not containing it:
object Example {
class C(val i: Int = C.DefaultI) { }
object C { protected val DefaultI = 5 }
}
scala> (new Example.C).i
res0: Int = 5
scala> Example.C.DefaultI
<console>:11: error: value DefaultI cannot be accessed in object Example.C
Example.C.DefaultI
Alternatively, you can alter the scope of the protected keyword to include the enclosing object:
object Example {
def value = (new D).hidden
class D(val i: Int = 5) {
protected[Example] def hidden = i*i
}
}
scala> Example.value
res1: Int = 25
but here you ought not name the outer object the same thing as the inner class or you'll have trouble referring to it from within the class.