How can I have call site generic in interface prop...
# getting-started
u
How can I have call site generic in interface property?
Copy code
interface FooProvider {
    fun <T> getFoo() : T <--- works
    val <T> foo: T <--- doesnt
}
d
You can't, because it does not make any sense.
s
I was gonna say, how on earth do you plan on using that
u
why would it not make sense? its same thing as androids
fun <T> findViewById(): T
d
No. A property has a fixed type...
u
but this is interface, I just need a getter
and wanna be more idiomatic to have property syntax rather than getFoo()
d
Yes, but... a property still has a fixed type.
u
so I am SOL?
a
move the `<T>`:
Copy code
interface FooProvider<T> {
    fun getFoo(): T// <--- works
    val foo2: T //<--- works
}
u
yea, but I rather not have it at class level
s
@Alan Evans they’re asking for call-site generics, your example wouldn’t provide the API they’re looking for
u
basically I want a getter method with "kotlin property sugar"
r
That's not idiomatic. Getter doesn't mean "any function that starts with get". What you are trying to create here is a function, not a property.
👆 1
u
then why are vals allowed in interfaces
if that were the case interfaces would be fun only
s
I don’t follow. There are perfectly valid use cases where you’d want implementing classes to provide a
val
u
@Shawn are you replying to me or ruckus?
s
you
u
im arguing for vals, he against afaik
s
no he’s not.
u
then I dont follow, If I am trying to create a function, not a property, then what is a val in interface? its abstract getter, to be implemented in implementing class
s
You’re trying to create a function because it takes a type parameter to determine what it should return
properties are just properties
sure, they can be backed with functions, but only in cases where they’re isomorphic to the notion of just accessing a field on a given object
u
true, but, interfaces have no state (non static), therefore everything they declare is abstract functions,
by that logic properties on interfaces cannot exist, since theyre just function contracts
1
r
Sorry, I guess I didn't make that very clear. I meant from a conceptual stand point, what you are trying to make is a function. I wasn't arguing against `val`s in interfaces, just that your use case doesn't make sense as a property.
s
Interfaces having no state doesn’t really have bearing on whether or not they can mandate that implementing classes provide a val or not
u
thats okay, I do want vals with actual backing field in implementing class
r
How can that be? You can't have a backing field if you don't know the type.
u
yea sorry thats not right, I just want the
Copy code
override val appComponent: AppComponent
        get() = ...
in implementing class
s
Interfaces describe the shape of the implementing class, and because of how properties are implemented within Kotlin, you can have them within interfaces. A property getter that needs a type to return a value is not a property getter, therefore you can’t use a
val
to accomplish what you’re trying to do - that fact is not a contradiction of the validity of having properties within an interface
u
so val foo: Foo get() = .. is not a getter?
r
I may be missing something, but that seems like you do want the type on the interface...
(Like @Alan Evans said)
s
val foo: Foo get() = ...
is a valid getter,
val <T> foo: T get() = ...
is not
u
well, that just feels like semantics to me, but if youre right then okay
s
There’s no generic parameter in the first example, they mean definitively different things
r
Not just semantics, it has a logical bearing. Functions can be polymorphic, data can't. If you have a backing field, how can it be polymorphic? It doesn't make sense.
u
exactly, when you dont have the field
basically I just dont want to type
()
😄
r
Ah, well, it's important to realize
()
has semantic meaning. While I understand the urge to save characters, doing so at the cost of readability is a Bad Thing™.
u
obviously im not obsesses with the 2 chars, but from callsite it has better ux, clearer intention
that it just provides value, doesnt futz with anything else
r
I must be still be missing something then, because it sounds to me like it would be less clear intention.
u
imagined callsite:
fooProvider.foo<SomeFoo> vs fooProvider.foo<SomeFoo>()
p
So assuming you would be able to define
val <T> foo: T
in interface, how would you implement it in a class? In your example:
Copy code
override val appComponent: AppComponent
        get() = ...
there is no
<T>
here anymore.
u
same way it would look on functions, it would stay
T
r
Exactly, the first one doesn't make sense to me. It may be "prettier" by some definitions, but it doesn't make logical sense. I expect
foo
to be a value there, so how can I dictate what type the value is when the class already has it.
u
override val appComponent: T get() = ... some value
p
how would you return
T
? just cast
as T
?
u
yes
r
So what should happen if I say
fooProvider.foo<String>
?
That's perfectly legal by your definition.
u
casting crash
same as with functions
okay Ill type out what the use case is, you tell me if it makes sense
r
That's the point, it's not a function from a user standpoint. The fact that functions are used to implement the functionality is an implementation detail. The user expected data, not functionality.
u
guess youre right
r
A function does stuff (thus the name), data doesn't.
u
but -- he gets data, thats why in my mind it fits property
p
So you want to write
fooProvider.foo<SomeFoo>
instead of
fooProvider.foo as SomeFoo
?
u
@Pavlo Liapota pretty much, but the generic would help me in type inference, avoiding spelling it out
r
The purpose of generics is to make your code type safe, not pretty. The fact that they are pretty is a testament to the language designers.
u
@Ruckus well, if safety is key then you cant have callsite generics 😄
because youre almost always casting
r
Yes, it gets data, it isn't representing data.
Any function that returns gets data, that's different from being (or representing) data.
u
I'd 100% agree with you, if there were no vals without backing fields
since they do, you can technically put logic there
and only thing stopping you is convention
r
Yes, that is precisely true
u
then its not different to function that has a return value
r
Convention is very important for understanding, readability, and efficiency. Don't dismiss it because it's possible to get around it.
u
only thing is different call site syntax
im not dismissing it, im just showing the hole in your logic imo
r
Many of your arguments hold just as true for not using any modern language features. We should be using pure assembly.
s
a) just because you can doesn’t mean you should b) we have different constructs that intentionally mean different things - just because they’re similarly handled under the hood doesn’t mean the abstraction on top is obviated
why even have strings? they’re just numbers underneath
u
what? cmon man 😄
whats the difference between fun foo():Int = 1+2 vs val foo: Int get() = 1 + 2
r
I think we're arguing the same side here, just coming to different conclusions.
u
asuming the 1 and 2 came from some place else, not constants
p
Anyway, you can have a call site generic in property only if you do an unsafe cast. So there is no sense of implementing this feature in a language. Right?
And like @Ruckus said:
The purpose of generics is to make your code type safe, not pretty.
u
@Pavlo Liapota I know its not the best thing ever to rely on casting, but its the reality of some use cases, see findViewById in android
r
@ursus There was a very similar argument a while back where Uncle Tom used the same logic to claim null safety in Kotlin was pointless, because you can get around it if you try hard enough.
😆 1
u
I disagree, your claims hold true for world where only functions and field backed properties exist
if the "hollow" vals exist, then theyre just syntactic sugar for functions
r
No, they don't. They hold true where you expect properties to be data (from a conceptual standpoint) and functions to be functionality (again, from a conceptual standpoint). Implementation is a separate beast, but the choice of conventions is vital in building a good mental model.
The language designers (of any language) decide the importance of the conventions and enforce them accordingly.
p
So what do you want to achieve? Just save two characters
()
? Or use generics for type inference?
r
In the end, it's all just conventions. My point is that those conventions are extremely important.
u
@Pavlo Liapota both, I just find it weird to have getFoo() in kotlin
s
you have this backwards - vals with custom getters aren’t syntactic sugar for functions, they’re properties that can be backed with an accessor which takes no arguments and whose result can be considered more or less isomorphic to the data it’s supposed to represent
p
you can call it
foo()
🙂
s
having a function contract that relies upon a call-site
T
breaks that notion and takes it out of the realm of properties
r
@ursus If I may, the Kotlin way of doing it is exactly why you should use
getFoo()
here. It makes it clear that the data is being fetched, and there are generics in play. Using
getX()
in Kotlin only feels strange because Java, which didn't have a good way to separate the concepts of accessing data vs fetching data (if that makes sense).
u
@Ruckus
They hold true where you expect properties to be data
what does "data" mean to you?
r
Unless you are just getting data, in which case it doen't make sense to make it generic
u
man, thats the same thing in my head to a function that has no params and has a return value
i.e. a getter
r
There is a huge difference between a "function that has no params and has a return value" and a "getter".
s
@ursus maybe that would be true if
fooProvider.<SomeView>foo
returned the exact same thing as
fooProvider.<String>foo
in which case, why even have the type
u
T: Any is just for brevity, its gonna be bound
r
For example:
doSomehtingAndReportSuccess(): Boolean
isn't a getter. From an implementation standpoint, sure, the computer doens't really see a difference. But code should be for humans to read and only incidentally for computers to execute.
u
and I wanna hide the cast inside, youd be cooler with fooProvider.foo as SomeFoo?
@Ruckus man, im still not sold, because you can add logic there, not only by breaking the convention, but by delegates, etc....(lazy)..
which are perfectly idiomatic
s
you’re familiar with the concept of code smells, right?
r
Agreed, but that's still an implementation detail. What matters is the mental model your trying to build for your user.
u
@Shawn I am dont worry, the actual use case is dagger in multimodule, so were already dealing with limitations
r
And the user comes in with certain expectations due to these conventions
u
exactly, and whats the point if you can .. idiomatically add logic and also break em via ignoring convetion
then you can question every property
its all just make belief imo
and syntactic sugar for getter
s
that “make belief” is better referred to as an abstraction, and that’s kind of what we rely on to write concise, unambiguous code
like sure, you’re right, maybe someone can abuse custom getters
that doesn’t invalidate the notion of having them in the first place
r
Sure, "make believe" is really just another way of saying "convention". Yes, you can break them, and often you do have some logic in getters, but that should be to support the mental model, not break it.
u
okays lets forgive breaking the convention .. id argue delegates are logic glued onto the properties
but its idiomatic so you give it a pass
r
From an implementation, yes. But the point is to represent it to your user as if it was data to provide a useful abstraction.
u
I just dont see the boundaries of "data" is you say
id be cool with "just return current value"
r
For example:
Copy code
val nameObservable = ObservableValue("name")
var name
    get() = nameObservable.get()
    set(value) = nameObservable.set(value)
From an implementation standpoint,
name
is logic. From a user's standpoint, it's not.
u
what are the parameters for "data" in eyes of user?
uncalculated immediatly returned value?
r
That depends on the use case.
I know that's a vague answer, but that's by design. That's the point of abstraction.
u
why, it should be the same everywhere
r
No, it shouldn't
u
basically what we are arguing is if getting stuff is doing stuff
r
And both of those concepts only exist for users. For a computer they're the same thing.
u
id be okay with such separationg, but if you can do stuff while user expects to "only" get stuff
then theres no distinction, other than syntax
r
Sure, but we seem to have a different idea of how important that artificial distinction is. I'm arguing that it is very important.
s
The syntax means something
u
yes, and it lies to you!
thats like fun foo(): Foo and you get String
r
All higher level programming concepts "lie" to you then.
The distinction between data types is a "lie". That's just another way of saying "make believe", "abstraction", and "convention".
u
yea, thats why data class shouldnt exist and only structs
r
Structs are just as much of a lie
Basically anything other than your CPU's word-type, byte, and bit is a lie.
s
40 72 75 63 6b 75 73 74 62 6f 6f 6d 20 79 65 73 2c 20 70 72 65 63 69 73 65 6c 79
u
I think youre arguing with extremes
in a sense you are right, but
if I create a new object, I dont expect it to be a function, etc
s
it’s taking your argument to the logical conclusion
so what if you don’t expect it to be a function?
{ -> }
is just an object of sorts under the hood, right? Are you lying to yourself?
u
I dont think so, if such were the case then nothing holds true in kotlin because its electrons traveling in the hardware
r
Exactly, but that's just an expectation based on the conventions of the language.
s
you’re right, it is just electrons traveling in hardware
by your argument, abstracting on top of that is useless because it’s lying to you or something
r
u
but there is difference between saying data class SHOULD NOT contain logic, even though they can
and object == function, in kotlin
orwhatever if statement == for loop
even though its just instructions etc
r
... which is exactly what we've been saying
u
but there are hard rules and conventions
s
like I said, just because you can do something doesn’t mean you should do something
u
okay im lost, im right goddamit 😄
🧌 1
r
What hard rules are there?
u
yes, im just worried about having my expections broken
-- minimal constructs of a given language
for, if, while, class, function
property is not such thing imo
r
Those are just conventions enforced by the language designers. They can still be usually worked around with enough hackery.
u
true, but theyre axioms in the given layer
or whatever is the fancy word
s
lol “fancy word”
those “fancy words” are used to concisely refer to commonly-understood concepts
r
Only by convention.
u
jeez shawn, im not english, my math-y terms were different in school unfortunatelly, so im guessing the terms
s
that’s like saying “function” is just a “fancy word” for “process that takes a thing and returns a thing” and therefore I shouldn’t say “function”
r
While there are many similarities, programming isn't math, and many mathematical concepts don't hold up very well in programming, axioms being one of them.
u
well, then you cannot argue about anything, if no axiomatic baseline is established
r
I don't think Shawn meant to offend, just that your "fancy words" phrase was a good lighthearted way of implying the difficulties of jargon.
👍 1
u
I do agree its all just electrons, but to create some abstract model, you need to establish some base line
which would not be questioned .. axiom?
s
the only real axiom is that there are bits and they can be turned on and off
everything on top of that is abstraction that we use to create more complex systems
r
you cannot argue about anything, if no axiomatic baseline is established
Sure you can. You just need to establish a convention. There's no axiomatic truth in programming. With the advent of Quantum processing and other non-binary processors, "bit" is just a convention.
s
ah, good point
not even the bit is an axiom lol
u
thats so nihilistic
why do anything if its al lthe same,
r
The point is we don't need axiomatic truth. We're not trying to "prove" truth with programming, just do something useful.
s
the my point is, the abstractions we draw over whatever baseline we have are meaningful
and just because you can back a
val
with something that strongly resembles a function doesn’t mean there’s no point in treating them differently when writing said
val
or consuming it
r
I'm not saying "it's all the same and there is no truth", just that the idea of axiomatic truth is a mathematical concept that doesn't apply to programming.
u
but if you take kotlin as baseline, then if is not for and for is not a class
but property without backing field is a function goddamit 😄
r
A good example is equality. Mathematics has very strong axioms to define equality exactly, but when programming, equality is a business decision. That's not because programming is worse than math, just that they cover different domains.
u
its a fake construct, which should have been strongly enforced by language to be correct
s
it kinda is - you can’t pass a parameter to the property getter, and you can’t give it a type parameter…
u
you can even pass its params internally lolz
I still believe hollow property is bad design
I struggled with it in RxJava too, should by fooObservable be val or fun? kotlin would have believe it should be hollow val if there are no parameters
and what if I need a param? then its a fun
so my api is I provide 4 observables, 3 are vals, 1 is fun .. its a mess
asymetric, ugly
r
How about this:
Copy code
class Bounds(
    var minX: Double,
    var maxX: Double,
    var minY: Double,
    var maxY: Double
) {
    var width: Double
        get() = maxX - minX
        set(value) {
            maxX = minX + value
        }
    // Same idea for height
}
u
width is 100% function imo
r
Why? (I'm not fighting you, just trying to make a point (though apparently not very well 🙂))
u
because width is abstract "property" of the rectangle, its infered from its coordinates
kotlin properties should be undividable uninferable
english failed us 😄
or was english your point? overloaded term 😄
r
But you know nothing about the domain that Bounds object is used in.
Why should Kotlin properties be "undividable uninferable"?
u
because neurons in my brain 😄
I just feel its same as color = r,g,b
r g b are properties, color is a function that composes the channels, channels are the smallest "atoms", any composite is a function
r
But that ignores the existence of any other color space or representation. What about HSL?
s
I feel like this example might get a little out of scope of the discussion lol
r
Agreed, we're getting a bit off topic. Sorry 🙂
u
no were not, were questioning the matrix, i like that, no medium article gives me this
or 9 to 5 colleagues
s
I also had the HSL thought (also CMYK, L*a*b*, etc)
r
Sure, but a thread in #getting-started is probably not the best place for an existential crisis...
u
slack is basically unsearchable so were cool lol
I dont know about HSL enough, but I dont see the point
r
Besides, I don't know where you guys are, but I haven't even had lunch yet. It's a bit early to question my own existence when I still have a lot of work to do today.
s
@Ruckus I kinda gave up on not having existential crises in odd spots a while ago; #getting-started is not the weirdest place I’ve discussed one lol
r
Fair point
u
all I arguing is to question stuff, even though smart people like andrey made it, and not just take it like axioms
and then bend the definitions to fit it, thats confirmation bias
s
in any event, to unwind the stack a bit,
width
is a computed property of
Bounds
there - the computation relies only upon properties within the class and doesn’t have any side effects. I think that makes that accessor safe to ship to a consumer labeled as a property
r
Questioning stuff is good. It leads to excellent discussions like this one that can help each other understand and uncover logical flaws.
s
it is an inherent trait of the concept
Bounds
is supposed to represent
a
are you still arguing what defines property and what is function?
r
"bend the definition to fit" isn't confirmation bias in programming (at least as I see it), it creating conventions.
s
237(+1) replies in, we still haven’t come to a resolution
r
@alex More or less yeah, though it's gotten a bit dicey here and there 🙂
@Shawn I don't think there's a resolution to be made, at this point we're just desperately hoping to understand each other. I guess that's a resolution, so never mind.
s
¯\_(ツ)_/¯
a
@ursus Property is just a fancy name, it doesn't have anything specific about it's definition. C# docs state it clearly: "A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of methods." Basically it is syntactic sugar.
u
haha, take that guys
r
... take what?
u
I read that and It fits my case 😄
r
That basically says "properties are a convenient convention for data access" with some discussion about the implementation details.
u
you almost had me at the
width
because philosophically it is more of a property than a function, even thoughits computed
s
I guess you could consider it sugar for declaring getters and setters, but that doesn’t mean a property isn’t conventionally treated differently than you would a function…
u
but I kind of feel its because of english language
s
a hypothetical accessor that takes a generic parameter and casts data doesn’t “promote the safety and flexibility of methods”
not as I understand it, anyhow
r
you almost had me at...
I wasn't trying to get you or deceive you in any way.
u
@Ruckus im not saying that, relax, i mean you almost convinced me 😄
r
Ah, sorry. My mistake.
u
yes, okay, I can give you width being a property
because it is a quality of the given object, althogh only referential to the other "hard" properties
man, but if you look at it from call site, width is just a convenience for the user...
if it can be infered
r
That's my point. Why can it be a property? Why should/shouldn't it be a function? It all comes down to whatever convention we agree on. The definition I used for width works for a certain common use case, but falls apart quickly if you'r working on non-euclidean geometry, or possibly even something other than geometry that happens to have a concept of "x", "y", "width", etc.
"width" may be a much more complex idea that should be a function for semantic purposes.
a
@ursus You give property too much meaning. It's a language feature, called "properties". It's the same construct as "for" or "when". I think your misunderstanding comes from mixing two ways of looking at things.
1
u
I dont see how "its artibrary" proves your point
r
@alex Excellent way to put it. I think I'm getting too philosophical.
u
yes, thats why I want
Copy code
val foo: T
 get() = whatever as T
the end 😄
r
But that's not a language feature. Likewise: the end.
u
it should, the end3
okay thank you guys, i enjoyed this
s
The fact that you can assign meaning or distinction there despite the fact that “it’s arbitrary” means that there is meaning in the distinction and it’s not worth treating one exactly like the other
shrung I hope you got something out of this lol
u
yea thats true
if there is a difference, then there is a difference
r
Agreed, It was a good discussion. Hopefully we at least understand better where each other is coming from, even if we don't agree with each other's conclusions (because you're wrong 🧌 )
u
just the projection of the problem is wrong if it yields uncertain answers
same as in quantum, there are good questions, there are bad questions
r
the problem is wrong if it yields uncertain answers
In math, sure. Not so much in programming.
u
there are no probabilities in quantum if "good" question is asked
they just wanna be fancy and answer anything, so they give you probabilities for bad questions
r
😕
u
like, what is the radius of a line .. answer is fuck off
r
You and I must have studied very different quantum physics.
u
I didnt, thats why I make such sweeping claims lol
r
That is... not really a good way to go about doing things.
u
I know, I went too deep
but hes right in that if there is a rule in randomness, then its not random, and if the rule is fuzzy, then the projection is wrong
minus the quantum tangent lol
r
If you're referring to @Shawn's comment, I don't think he said anything about the fuzziness of the concept. If there was no fuzziness in concepts, there would only be one language and one way of doing things. The fact that concepts are fuzzy is exactly what makes programming so useful.
But I think I'm talking myself in circles, so I'm going to bow out before this whole thing flares up again.
1
🙇‍♂️
u
😄
thanks a lot, bbye
👋 1
(enjoy being wrong)
🧌 1
🧌
a
I skipped to the bottom half way through but I think you can also use inline lamda params bases on your use case.
fooProvider.usingFoo { Int it -> it * 5 }
. Haven't tried it. Also I haven't worked with Android but I'm not completely sold on design of
getById
returning
T
arbitrarily. I think it should at least take in something like a Key<T> type but then again it's not really solving the problem.
Also the call site generics are especially helpful with inline fun and reified generics.