Home > OS >  Kotlin: class instance variable value-parameter error
Kotlin: class instance variable value-parameter error

Time:05-21

First post - New to Kotlin so beginner-learner. Please be gentle if my terminology is not quite up to scratch yet!

I'm attempting to call a parameter that i've declared in a secondary constructor within my main function variable but it doesnt format like the primary constructor variables and doesn't let me initialise a value that can then be called like the others.

Problem line: (it's the 'age =' bit)

var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )

full syntax below:

fun main() {
    var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )
    var phoneOne = MobilePhone("Samsung", "Galaxy", "S20",)
    println("What is your hobby?: ")
    phoneOne.hobby = readLine().toString()
    phoneOne.stateHobby()
    phoneTwo.hobby = "Plumbing"
    phoneTwo.stateHobby()
    phoneTwo.age = 32
    println("PhoneTwo is $phoneTwo.age years old")

}

class MobilePhone(osName: String, brand: String, model: String) {

    // member variables - Properties - variables within a class
    var age : Int? = null
    var hobby : String = "Watch Netflix"

    // Initializer block
    init {
        println("A new mobile phone was created called $osName which is "  
                "brand $brand and it's model is $model")
    }

    // member secondary constructor
    constructor(osName: String, brand: String, model: String, age: Int):
            this(osName,brand,model){
                this.age = age

            }



    // Member function - functions within a class
    fun stateHobby() {
        println("Your hobby is $hobby")

    }

CodePudding user response:

This is about the syntax of calling a method/constructor in Kotlin, not about secondary constructors as such (which are called in exactly the same way as others).

First, let's review the syntax for calling a method (or constructor).  You can just list the values alone (just as you do in Java, C, or many other languages), e.g.:

MobilePhone("Apple", "iphone", "X", 5)

However, Kotlin also allows you to specify the names of the parameters they're being passed to, e.g.:

MobilePhone(osName = "Apple", brand = "iphone", model = "X", age = 5)

That's more long-winded, but you may find it easier to read and safer (especially if there are multiple parameters with the same type). It also lets you put the parameters in any order, e.g.:

MobilePhone(model = "X", osName = "Apple", age = 5, brand = "iphone")

You can even mix and match the forms, as long as the unnamed parameters come first, e.g.:

MobilePhone("Apple", "iphone", age = 5, model = "X")

This feature is only mildly useful on its own, but is very handy for a related feature: the ability to specify default values for some or all of the parameters. (See that link for more.)

Hopefully this illustrates why the problem line doesn't make sense:

var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )

That looks like you want to call the secondary constructor, passing the values "Apple", "iphone", and "X" to the first three parameters, and then naming another parameter but without passing it a value. This is of course a syntax error.

If you have a value to pass for the age, then just pass it, either with the parameter name:

var phoneTwo = MobilePhone("Apple", "iphone", "X", age = 5)

or without:

var phoneTwo = MobilePhone("Apple", "iphone", "X", 5)

Or if you don't have a value, then simply call the primary constructor instead:

var phoneTwo = MobilePhone("Apple", "iphone", "X")

Incidentally, this means that your class doesn't actually need a secondary constructor at all. You could simply include the optional parameter in the constructor, with a default value:

class MobilePhone(osName: String, brand: String, model: String, var age: Int? = null) {

Then callers can either specify the age param, or omit it (and get the null default value).

In fact, features such as multiple constructors, method overloading, and builder classes tend to be used less in Kotlin than in some other languages, because default parameters cover their main use cases.

CodePudding user response:

I'm not sure what you're trying to do exactly, but hopefully this covers it! This:

var phoneTwo = MobilePhone("Apple", "iphone", "X", age = )

is trying to call your secondary constructor, and you're using a named argument for one of the parameters (age) but you're not actually passing a value for it. If you do, it'll compile

MobilePhone("Apple", "iphone", "X", age = 3)

You don't actually need to name the argument there - if you just pass an Int as the 4th parameter, it'll match your secondary constructor's signature (number of parameters, correct types for each, in the same order), so the compiler will know that's what you're calling. If you omit it, it'll match the primary constructor. You can still keep the name there for readability, if you like.


But you can actually duplicate the functionality you have there with a default parameter, which is where you supply a value to use if the call doesn't specify one:

class MobilePhone(osName: String, brand: String, model: String, val age: Int? = null) {

    // member variables - Properties - variables within a class
    var hobby : String = "Watch Netflix"

    // Initializer block
    init {
        println("A new mobile phone was created called $osName which is "  
                "brand $brand and it's model is $model")
    }

So now, age is a parameter on the primary constructor - if you don't supply it (just calling with the first 3 items, which are required because they don't have defaults) then it defaults to null.

By making that parameter a val (or a var if you like) it becomes a class property you can reference later, instead of only being accessible during construction. So you can remove the var age property inside the class, because this is basically the same thing (and they'll clash anyway)

And now that you have a primary constructor you can call with or without the age parameter, there's no need for the secondary one anymore! This is where named parameters really come in useful - if you had defaults for each of those params, you could just supply the specific ones you're interested in, by using their names


oh also, "PhoneTwo is $phoneTwo.age years old" won't work - if you're just referencing an object, you can do $phoneTwo, but anything more complicated (like accessing one of its properties, or any method calls or more complex expressions) have to be wrapped in ${}

println("PhoneTwo is ${phoneTwo.age} years old")
println("PhoneTwo is ${phoneTwo.age * 365} days old")
  • Related