Is there any way to make a custom property required in QML? E.g., something like:
property required int numRows
I want to enforce that the user of the component passes a certain property, because the component will not work without it.
There is a required option was added in QT 5.15 qml: qt doc.
The syntax is the following:
required property <propertyType> <propertyName>
Thanks Marcin Orlowski for update
no, you can't. The most robust way is simply to give a valid default value to the property.
a workaround could be to give an invalid value (e.g -1) and check value in the Component.onCompleted slot of your item and show a console.log if property wasn't valid...
but prefer the first way, a component should always be usable with default values, for reusability goals!
Qt trolls have told themselves that Component.onCompleted is not the preferred way to do most things, but a hack the had to implement.
The best possible is to use a declarative-style enabler, something like this would be ideal:
MyItem{
property int myvalue: -1
enabled: myvalue != -1 // Use other number if neccesary
}
This would work for enabling interactive elements, but more interesting stuff can be made like:
MyItem{
property int myvalue: -1
onMyvalueChanged:{
enabled = true
callMyInitFunction(something)
}
}
That will trigger when the user changes the value, then you can call other functions or initializers. If you want to init only once, you can check if it's disabled.
MyItem{
property int myvalue: -1
onMyvalueChanged:{
if (!enabled){
enabled = true
callMyInitFunction(something)
return
}
// Stuff to do of already initialized
callOtherStuff(otherThing)
}
}
Finally, by reading the words you wrote "passes a certain property" it seems you might instead create a javascript function for the object and call it.
MyItem{
property int _myprop: 0
function launch(param1, param2, param3){
_myprop = param3
// do stuff
}
}
Then you would call it by launching it instead of creating it, this might work for a reusable Dialog, depends on your use case.
Of course there are several ways to do things depending on what you need.
Related
I'm trying to get the type of some class properties in order to strongly typing my Kotlin Code.
In typescript, we can do this (stupid examplebut this is to explain)
class Test {
private _prop:string
constructor(val:Test["_prop"]){
this._prop = val
}
public get prop():Test["_prop"] { return this._prop}
}
const t:Test["_prop"] = "fdds"
The benefit here is that if I need to chnange the type of "_prop", no need to refactor the whole code, as the type is find thanks to Test["_prop"].
Is there a way to do this in Kotlin ?
I've seen reflection functions in Kotlin, but can't get what I want
Kotlin code :
class Test(val prop:Int) {
fun ppr() {
println(prop)
}
fun getProp():Int {
return prop
}
}
fun main() {
println("Hello, world!!!")
var t:Test = Test(4)
t.ppr()
var a:Int = t.getProp() // how to change :Int by "return type of func Test.prop
}
What you're trying to do is the opposite of strong typing. The point of a strong-typed system is that you're defining exactly what things are, and the system requires you to interact with those things correctly, and prevents you from doing things those types don't support
You're working with specific types and defined type hierarchies, and the way you can interact them is strongly enforced. It's possible to go outside the type system, e.g. with unchecked casts, or by reflection (which can get close to throwing the whole thing out completely) - but that's losing the benefits of strong typing, the guarantees and assistance it can provide, and makes errors a lot more likely
Basically if you want to change the type, you're supposed to refactor it. That lets the system handle it all for you systematically, and it will point out any problems that change might introduce, so you can resolve and handle them. This is another benefit of a strongly typed system - it can help you in this way
If you want to stay within the type system, but just want to update a type and avoid creating changes in a bunch of files, then #Sweeper's typealias approach will work - kinda abstracting a type definition away to one place (and you can give it a more meaningful name that doesn't reflect the specific type it happens to be right now). But if you meaningfully change what that underlying type is, your code will probably have to handle it anyway, unless you're just doing a common call on it like toString().
I might have got what you're asking for wrong, but I wanted to point this stuff out just in case, since you were talking about reflection and all!
You can't do it exactly like that in Kotlin, but you can declare a type alias, which sort of achieves the same result - enabling you to change the type of multiple things by editing only one place.
typealias PropType = Int
class Test(val prop: PropType) {
fun prop(): PropType {
return prop
}
}
To change the type of both, just change the typealias PropType = Int line.
However, note that you don't actually need to do this if you just want to write a getter. You don't need to explicitly write getters if all it does is just returning the property's value. If you want to do something extra in the getter, you can do:
class Test(prop: Int) {
val prop = prop
get() {
// do something extra in the getter
println("getting prop!")
return field // return the underlying field
}
}
The getter will be called whenever you access Test.prop, and again, you only need to change one place to change the type of the property.
I'm currently using Reflection to inspect an element at runtime using the class.memberProperties function. The type of properties is collection<KProperty1<I, *>> so I run through each of the KProperty objects to find the one that I want by checking if the name is equal to "nameIWant", though I would much rather be able to get the instance of the property from the KProperty by using the .get() method on the property, so that then I could do a check such as:
if (property.get(receiver) is ClassIWant) {
//Do something
}
My code looks like this:
val properties = request.payload::class.memberProperties
properties.forEach { property ->
run {
if (property.name.equals("nameIWant")) {
}
}
}
So far I've been trying to use the .get() method on the KProperty1 type but it takes an argument receiver of type Nothing. I'm not able to work out what I need to pass in order to call the .get() method and get the particular instance of the property. I've also checked the documentation here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property1/index.html but it hasn't really helped at all.
justPassingBy is right. but the more simple way is to use:
myObj.javaClass.kotlin.memberProperties.foreach { property ->
property.get(myObj)
}
If you want to get the value of the property, cast the class into invariant type.
instance::class.memberProperties.first() // returns KProperty1<out Instance, *>
(instance::class as KClass<Instance>).memberProperties.first() // returns KProperty1<Instance, *>
If your KClass<Instance> is KClass<*>, use Any as Instance.
Why did the KProperty.call take Nothing as receiver?
Because instance::class returns KClass<out Instance>, which propagates the covariant type argument down to the property, which it becomes KProperty<out Instance, *>, which narrows down the possible method receiver to any subtype of Instance, but because we do not know which, we can not safely supply any instance of Instance, as show by the rules of variance, which here limit the generic type argument to Nothing, which means it is impossible to call the method at all.
Why is ::class designed to be covariant?
To guarantee safety. This has been an issue of great debates as it seems somewhat illogical.
If you want to know the type of the value that the property can return, use
property.returnType
It returns a KType, wich is Kotlin's version of Java's Type, which is a more generic concept of a Class (which is one of the implementations of Type).
If you need to 'convert' the KType to a KClass, you need to do the same as if you needed to convert Type to a Class, which is get the raw type of the type. Raw type is type stripped of the any generic information, yes, an erased type. The way to do this is (seemingly) more complicated (involves handling each possible KType/Type implementation) and I recommend checking for answer to this problem separately.
You will be able to reuse Java implementation (that you will surely find on your own) using:
kType.javaType.covertJavaTypeToJavaClass().kotlin // returns KClass<*>
Corrections in your question. I recommend using the proper terms if you wish to receive proper answers:
* I in your question is type of the method receiver, not the value of the property
* collection is not a type, Collection is
* property is ClassIWantis ambiguous as property.type is type of the value in the property and property::class is simply the property implementation, is is also an instanceof check, but in reflection, you need to use KClass.isSubclassOf, or what is known in Java as type.isAssignableFrom (watch the call order), which then makes your condition to be ClassIWant.isSuperclassOf(property.type.getRawType())
* instance of the property properties have values, not instances. Only classes have instances. Instances are values and values are instances (of some class), but you must still say instance representing the value of the property
You can create a KType for your ClassIWant and then check the property's returnType. It will be something like this:
val properties = request.payload::class.memberProperties
val desiredType = ClassIWant::class.createType()
properties.forEach { property ->
if (property.name == "nameIWant" && property.returnType == desiredType) {
//todo
}
}
btw you can cast your property variable to correct type and use get
val properties = request.payload::class.memberProperties
properties.forEach { property ->
val value = (property as KProperty1<Payload, *>).get(request.payload)
if (property.name == "nameIWant" && value is ClassIWant) {
//todo
}
}
prop.getter.call(obj) as String?
I'm new to properties and moved from the java to kotlin. I'm struggling with the properties, I learned much about it but initializing the properties are confusing me, when it should be initialized or when it can work without initialization.
Let me explain it by the help of code. Below is the code which is requiring to initialize the property when the back-end field generated, before posting the code let me post the paragraph from the kotlin official website.
A backing field will be generated for a property if it uses the
default implementation of at least one of the accessors, or if a
custom accessor references it through the field identifier.
Now here is the code below.
class Employee{
var data: String // because there are default implementation of get set
// so there will be a back-end field.
}
So I have to initialize it else compilation error.
Ok I can understand it as that some one can access it so there will be no value which can produce the wrong result.
Then I move next to understand it more, so I add custom getter.
class Employee{
var data: String
get() = "default value"
}
This also generate the back-end field so compilation error to initialize it. I can understand it as that there is no initialized value so compiler complain about it.
May be compiler is not smart enough yet to check that there is value which is giving result for this property by custom getter so don't complain about initializing just return that value when required.
But there should be not a problem if any one access it then a default value is already there, then why compiler still complain?
Then I move one step more to implement custom setter too.
class Employee{
var data: String
get() = "default value"
set(value){
field = value
}
}
Still there is the back-end field because we have accessed the field so compiler generate the back-end field.
Same error, should be initialized.
Then the final stage where it works fine as below.
class Employee{
var data: String
get() = "default value"
set(value){
}
}
Now I'm not accessing field in custom getter setter so there is not a back-end field. And it works fine.
So the final question when the property should be intialized? When there is a back-end field generated?
Yes this does not compile:
class Employee{
var data: String
get() = "default value"
}
but this does:
class Employee{
val data: String
get() = "default value"
}
so maybe the compiler by stating Property must be initialized for the wrong declaration, wants from you to admit that data is something that you can not change. I say maybe.
Now the part that does compile:
class Employee{
var data: String
get() = "default value"
set(value){
}
}
This is where you explicitly admit that whatever happens I will never set a value to data, and that's why the compiler feels fine.
Just to save you from more confusion, there's a lot of explaining about Kotlin in the Internet and you may find it very difficult to get familiarized with this relatively new language, but keep in mind that everything needs to be tested by you.
I found the below code in a web page:
class User{
var firstName : String
get() = field
set(value) {field = value}
var lastName : String
get() = field
set(value) {field = value}
}
and it is presented as compilable when it's not.
You kind of answered your own question. There's no backing field when you override both getter and setter, and don't access field.
About your "compiler not being smart enough": get() function is actually RAN at runtime, so writing a lot of compiler code just to evaluate if return value is static and should be injected as default is too niche of a use case.
If your getter depends on another field which is only initialized later, this would cause a lot of confusion as to what default value should be.
Consider this code, assuming value of provider is not defined:
var data: String
get() = provider.data
What would be a default value? Do you want a null? Empty string? Maybe entire object initialization should crash? Explicit default value declaration is needed for that purpose.
That's where idea of lateinit var came to be: if You're certain you will set value before performing any get, You can use this keyword to prevent compiler errors and setting default value.
class Employee{
var data: String
get() = "default value"
}
var means there are both a getter and a setter. Because you didn't write a setter, you get the default one, which accesses the backing field. So there is a backing field, and it needs to be initialized.
But there should be not a problem if any one access it then a default value is already there, then why compiler still complain?
Because that makes the rules simpler: all properties with backing fields must be initialized. This in turn may be because in Java fields don't have to be initialized and this is a known source of bugs. I would like to say it also avoids a possible bug, because presumably you don't actually want the setter's result never to be accessible, but initializing doesn't fix that problem.
I don't see any obvious problem with changing the rules so that a field only needs to be initialized when accessed in the getter, and maybe adding a warning when only one accessor uses field. But I may be missing something, and don't see much benefit to doing so either.
I am trying to learn Kotlin and TornadoFX. One thing I keep seeing is code like this:
val TextProperty = SimpleStringProperty()
var text by Textproperty
I've been reading up on the documentation
https://edvin.gitbooks.io/tornadofx-guide/content/part2/Property%20Delegates.html
so I've "absorbed" that they are useful for when values in a model change, but I need further help really grasping the concept. Something doesn't quite seem to be clicking. Does anyone have any examples, videos, etc. that demonstrate the purpose and usefulness of these property delegates?
The important point here is that JavaFX requires or at least prefers observable properties. Instead of declaring a mutable property, you would declare one of the JavaFX property types, depending on what property type you want (String, Double, Int etc). All you really need is to declare this property:
class Customer {
val ageProperty = SimpleIntegerProperty()
}
You can get by with just this, without using any delegates. However, if you want to mutate this property, you need to change the value property inside the property you defined, so the code looks like this:
customer.ageProperty.value = 42
This is cumbersome, so to make it simple, you'd want to add getters and setters. Doing this manually would look something like this:
val ageProperty = SimpleIntegerProperty()
var age: Int
get() = ageProperty.value
set(value) { ageProperty.value = value }
Now you can set the age of a Customer like this:
customer.age = 42
This is much more convenient, but you'd have to declare all that code for each property, so in TornadoFX we introduced property delegates that takes care of all that with a simple statement, so:
val ageProperty = SimpleIntegerProperty()
var age by ageProperty
The end result is the same, without you having to do any of the heavy lifting.
Just to be clear, this explains the property delegates, not why JavaFX properties are useful. JavaFX properties allow you to bind to a UI element, like a text field for example. Changes to the text field will be written back into the property, and changes to the property would be written back to the UI.
Once you can written something like
class C { var text by Textproperty }
all c.text = blabla will be compiled to TextProperty.setValue(c, ::text, blabla), and c.text will be compiled to TextProperty.getValue(c, ::text). This enables the library (the provider of TextProperty) to take over the operations on text.
Ref: https://kotlinlang.org/docs/reference/delegated-properties.html
I have a BOOL property and at the start this property equals NO. I want to set this property to YES from the start of my program, but with opportunity to toggle it.
For this, I made this getter:
-(BOOL)turn
{
if(!_turn)
_turn = YES;
return _turn;
}
This getter set my turn property to YES, but it makes it "constant", always YES.
Why?
I thought
if(!_turn)
construction is specially for the reason where you want set the "not set yet" object value
Can you answer me why this is so? And how can I set my property value to what i want. Thanks.
Look at your action table:
turn: False True
!turn turn = YES Do Nothing
When _turn is false, you flip it too true. When _turn is true, you do nothing (there's no else statement). Then you return the value of _turn. So yea, you are returning true in all cases.
To be honest, the design is not very good. If you want to set the initial value of the variable to a certain value, do that in the init method. Then provide another method that simply toggles the value:
-(BOOL) toggleTurn {
_turn = !_turn;
return _turn;
}
Usually the lazy initialization technique is used with pointers to objects, not with primitive types. This because a BOOL has only two possibile states: NO and YES, there isn't the "undefined state" which is usually associated with nil for objects.
The reason why it doesn't toggle is that you aren't toggling it, you are just setting it to YES when it's equal to NO, but you aren't handling the case when it's equal to YES. If you want to toggle it just do that:
-(BOOL)turn
{
return _turn= !_turn;
}
PS: Whoever could argue that your method isn't properly a getter, because you are altering the variable before returning it. So I suggest to just return _turn without toggling it, and to create another separated method to toggle the variable.
Also I would like to mention that what you are doing is not called lazy initialization, I'll show you a case of lazy initialization:
// In the interface:
#property(nonatomic,readonly) NSNumber* turnObject;
// In newer compiler versions it should be auto synthesized to _turnObject
// In the implementation:
-(BOOL) turn
{
// In this case I am not toggling it
if(!_turnObject) // Equal to if(turnObject==nil)
_turnObject= #(NO); // Equal to _turnObject=[NSNumber numberWithBOOL: NO];
return _turnObject;
}