Static-oriented syntax for invoking instance methods vs Simple static methods #6216
Replies: 5 comments 19 replies
-
cc: @jdunkerley @JaroslavTulach @hubertp @Akirathan @wdanilo @kustosz |
Beta Was this translation helpful? Give feedback.
-
Yup. That's a problem. I've been trying to make my head around the current behavior of
Once I wrote a blog post another assembly language. With the current syntax we can happily call Enso another assembly language!
Function defined on type and on instance must be defined on
...and object oriented paradigm sucks. Bringing inheritance into a functional language is the simplest way to ask for troubles! Brainstorming - Would: If the method is defined on
It is heavily used in and it works there quite nicely. |
Beta Was this translation helpful? Give feedback.
-
Right now However, if the above interpretation is accepted, then there would be no syntax for invoking |
Beta Was this translation helpful? Give feedback.
-
ObservationIf an instance method
We need to decide what SomeType.x means! Test Casefrom Standard.Base import all
Any.x self = "Any:" + self.to_text
type My_Type
Value f1
type With_X
Value f1
x self = "With_X:" + self.to_text
main =
IO.println <| My_Type.Value 33 . x # prints Any:(My_Type.Value 33)
IO.println <| With_X.Value 44 . x # prints With_X:(With_X.Value 44)
IO.println <| Any.x # Any.type.x[y.enso:4-24]
IO.println <| My_Type.x # prints Any:My_Type
IO.println <| With_X.x # prints With_X.type.x[y.enso:12-32]
IO.println <| Any.x (My_Type.Value 22) # prints Any:(My_Type.Value 22)
IO.println <| Any.x (With_X.Value 22) # prints Any:(With_X.Value 22) Please note that SolutionIf a method TL;DRThe answer to initial question is: SomeType.x invokes instance method with Thumbs up, if this is OKish. It is a minimal change so, we can turn it into a bug and implement it. |
Beta Was this translation helpful? Give feedback.
-
Got one more, very practical example when the current state of affairs fails: #6273 - if a Vector contains a type whose |
Beta Was this translation helpful? Give feedback.
-
The context
The PR #3764 introduced a calling convention that allows to write
Foo.method (Mk_Foo 123)
as a synonym of(Mk_Foo 123).method
(just to note, the status of the static/instance calls before this PR was also unclear, I'm not suggesting to simply revert the PR).It is not exactly clear why this was introduced, quoting the PR:
While such a convention definitely has some advantages in some contexts, in the context of Enso it is causing us quite a bit of trouble and I'd like us to discuss if we can remove it in favour of having separate instance and static methods.
The proposal
I would propose to remove the convention mentioned above and instead allow to define static methods in parallel to instance methods. Which method is called would be decided based on if the left-hand-side is an instance of an Atom or if it is a type - i.e. the method namespace of an instance and a type would be completely independent.
So I would suggest to allow the following code to work:
And print:
Currently, it would fail with
Method overloads are not supported: Foo.bar is defined multiple times in this module.
.The motivation
The existing issues
The current calling convention is a source of multiple issues.
The major issue is centered around problems with
to_text
(and in the past==
).Currently,
to_text
is actually defined in a way that is inconsistent to make it work - according to the rulesSome_Type.to_text
should be a closure that will take aMy_Type
and then return a text representation. But to make life easier, it returns"Some_Type"
by default - so this calling convention is not respected.However, if I override
to_text
on a type, it goes back to a 'default behaviour' and indeed if I do:it will yield:
So we can see that it goes back to the standard convention and
T2.to_text
actually returns a closure that is waiting for theself
argument. This is inconsistent withT1
.All this was mentioned in the following issues:
Error.to_text
causing problems Quick-fix for Error.to_text CCE #3357IO.println
breaking IO.println: Type error: expectedstr
to be Text, but got Function #5961Less "type safety"
When I write an instance method:
I expect the
self
inside offoo
to have typeMy_Type
. However, with this current convention, I can happily callMy_Type.foo 42
and getself : Integer
there, causing behaviour that is rather surprising.Current convention is not used anywhere
To the best of my knowledge, the current convention is not used anywhere in our codebase. Moreover, we are trying to design our libraries and workflows with the Component Browser in mind. It is oriented around executing methods on instances, i.e. it will always do
instance.method
convention - the CB will not generateType.method instance
calls. So this calling convention is not used and not likely to be used in the future.Alternative Solutions
I think switching to a simpler calling convention is the most robust fix here and will ensure that there are no inconsistencies.
The biggest motivation though is:
We need
to_text
on types to work correctly, as we rely on it both in our Test suite as well in some places where displaying error messages to the users.The trouble is mostly for functions that are expected to be defined both on type and instance. That is
to_text
and its friends (pretty
,to_display_text
), maybeto_json
and==
(as we want to be able to compare types for equality, likeif type == Integer then ...
).We could offer a fix just for this limited set of functions, where any override like defining custom
to_text
will only apply to instances, whereas when dispatched on types this would always call-in to the defaultType
implementation (as I don't believe we ever need ability to override these methods on a type itself, not on instance). This would ensure that stuff likeMy_Type.to_text
will return a Text"My_Type"
even ifto_text
for the instances of this type has been overridden.This is the least that we need to make
to_text
work correctly.However, to make this work - we are still overriding the calling convention and making
to_text
(and friends) behave differently - as now I cannot doMy_Type.to_text my_instance
anymore, since it will evaluate to"My_Type" my_instance
resulting inNot_Invocable
error.So we'd be making the language inconsistent with some functions not abiding to this calling convention. That's why IMO the best solution is to be consistent and drop this convention altogether.
Beta Was this translation helpful? Give feedback.
All reactions