objectionary / eo

EOLANG, an Experimental Pure Object-Oriented Programming Language Based on 𝜑-calculus
https://www.eolang.org
MIT License
1.01k stars 127 forks source link

Literals #85

Closed g4s8 closed 3 years ago

g4s8 commented 7 years ago

How to use literals in EO? Are they objects too or not? If yes, can we call methods of them? E.g.: 42.string() (returns "42")?

fabriciofx commented 7 years ago

@g4s8 I vote for everything be an object. So, your approach 42.string() returns "42", makes sense to me.

stain commented 7 years ago

0.5.string() and .5.string() as well? I guess that is the only tricky bit.. but we don't need to require a one-letter look ahead.

nqafield commented 7 years ago

@fabriciofx Why would you ever actually use 42.string()? (Except perhaps to demo the language in a REPL or something?) Why not just write "42"? It's quicker.

Would you also write "42".int() when you wanted 42?

fabriciofx commented 7 years ago

@pa9ey

I was thinking in something like:

m(int x) {
  x.string();
}

What do you think?

nqafield commented 7 years ago

@fabriciofx That's not a literal. :)

yegor256 commented 7 years ago

@g4s8 yes, we definitely need literals, but I don't like the dot-notation. Instead of 42.string() I would rather have string: 42.

As of literals, I guess, we need:

What else?

nqafield commented 7 years ago

@yegor256 Sure we need literals! But the main question was can you call methods on them. You don't seem to have addressed that.

stain commented 7 years ago

Are literal string values/arguments of type Text or String? Can you specialise a literal object? I think that could get weird..

Perhaps we can avoid literal method calls and object specialisation by saying that the literal will be of "native types" (e.g. int rather than Integer) and will be auto-casted to their corresponding type when passed as an argument.

Do we need literals beyond arguments, e.g. when @assigning within a constructor? The primary constructor should not use a hard-coded literal!

fabriciofx commented 7 years ago

@yegor256 What's the problem with dot-notation? Why you don't like it?

fabriciofx commented 7 years ago

@pa9ey What's a literal to you? To me, is a special case of variable. So, if I can do a x.string() to a variable, makes sense to me do a 42.string() to a literal too. What's your opinion?

nqafield commented 7 years ago

@fabriciofx I'm not particularly trying to express (or even have) an opinion. I just asked a bunch of questions. (Specifically about calling methods on literals.)

If you want my answers to those questions, well I already hinted at a possible answer to Q1. My answer to Q2 is: I can't think of a reason why not. My answer to Q3 is: No.

I like @stain's question too:

Do we need literals beyond arguments, e.g. when @assigning within a constructor? The primary constructor should not use a hard-coded literal!

It seems to me we don't.

g4s8 commented 7 years ago

This question is not about "why to use 42.string()?", but "are we able to call literals methods?"

@yegor256,

Instead of 42.string() I would rather have string: 42.

I agree with this, but in example you create new object instead of calling method.

@stain, I think you are right. If we allow literals only as constructor/method parameter, we'll solve loads of problems.

@pa9ey, you may want to use (42.0).string(locale), this return different string for some locales.

nqafield commented 7 years ago

@g4s8

This question is not about "why to use 42.string()?", but "are we able to call literals methods?"

Interesting. I think that for every question "Are we going to put x in the language?" one of the first questions we should ask is "Why would you want x in the language?".

Maybe not explicitly ask it, but we should always be considering that question. This seems to me to be a fundamental principle of all software development, not just languages and compilers.

Also, your replies to @stain and to me seem to contradict each other.

I think you are right. If we allow literals only as constructor/method parameter, we'll solve loads of problems.

you may want to use (42.0).string(locale), this return different string for some locales.

g4s8 commented 7 years ago

@pa9ey, sorry for misunderstanding, I mean that I like idea when we use literals only in constructors and method params, but I can imagine how to use literals in method body.

Why would you want x in the language?

I think it's impossible now to specify each case where literals can be used. E.g. in 42.string() they are redundunt, because we can replace it with "42", but what if integer type will provide another string method, like string(Locale locale)? To answer this question (Why would you want x in the language?) we need full integer, string, etc. types declaration, because without concrete examples we may only make a gues about it.

nqafield commented 7 years ago

@g4s8 Sure. But there's no need to guess. Let's wait till we need it rather than add it just in case.

yegor256 commented 7 years ago

@g4s8 @pa9ey @stain @fabriciofx I think that "calling a method" is something we should avoid in OOP. I'm not entirely sure, but that's what I feel. Calling a method means getting the result right now -- a procedural and imperative approach. While declaring a new object is declarative and object-oriented. Say, we need a string from a number. This is imperative:

text = number.string();

The calculation will happen right there, now, at the moment of calling method string(). Here is a declarative way (not EO syntax):

text = new IntAsString(num);

Here we're declaring a new object, which behaves like text, but the calculation is not yet done. It will be done, maybe, later.

See the difference?

yegor256 commented 7 years ago

And I don't like this: 42.string(). Even though Ruby is having that "syntax sugar", I would rather stay away from it. I'm in general against all "sugars" -- the stricter and simpler the code, the better.

nqafield commented 7 years ago

See the difference?

@yegor256 Yes, but that's not really what this issue is about, and it's also quite confusing.

Where are you going with this? It doesn't stack up with what EO is currently about. For example, if there's no code in constructors and you can't call methods, then the objects will never actually do anything!

Here we're declaring a new object, which behaves like text...

If no method is ever called, it won't behave at all! :)

yegor256 commented 7 years ago

If no method is ever called, it won't behave at all! :)

@pa9ey well, look at this fibonacci number calculator:

object fibonacci(1) as Int:
  Int @n
  ctor():
    fibonacci: 1
  ctor(Int n)
  Int int():
    if:
      firstIsLess: @n, 2
      1,
      plus:
        @n
        fibonacci:
          minus: @n, 1

Not a single method was called, but the object is a fibonacci number. Pay attention, plus and minus are not methods, but object constructors. I'm not entire sure where I'm going with this :) But I think that we need as less method callings as possible. Most probably none. I'm thinking about it...

nqafield commented 7 years ago

@yegor256 I like this idea (in theory) too. But I think this is the key issue I've been banging on about since before EO existed. I've posted this video before, somewhere in channel:

"Haskell is useless." https://www.youtube.com/watch?v=iSmkqocn0oQ

I think the EO that you're talking about is also "useless". (If you get my meaning.)

But at some point we have to address the "how do we also make it useful" question. We need a simple EO program, say, that asks the user for a digit (from 1 to 9) and then asks for another, and then outputs the sum of those two.

Then there will be methods. There will be behaviour.

If I was less "useless" myself, I would have written this by now. :)

yegor256 commented 7 years ago

@pa9ey I agree, there will be "methods", but they should not be called from object to object, only from decorator to encapsulated object. Take this as an example:

app:
  printed:
    sum:
      input_as_int: "please, enter first digit"
      input_as_int: "please, enter second digit"

We just create an app here, which is a copy of object app. When it become "alive", it calls printed.asText(), which calls sum.asText(), which calls input_as_int.asText(), which prints that intro message, and returns the value entered.

I'm against this:

Foo f = new Foo();
f.doIt(); // this is wrong

And I like this:

Bar b = new Bar() {
  private Foo f;
  void run() {
    this.f.doIt(); // it's OK
  }
}

Make sense?

mdbs99 commented 7 years ago

@yegor256 I could be wrong but, as I understood, using this idea all objects will have only one method.

nqafield commented 7 years ago

@yegor256 I just can't see it though. Too much is hidden in your example. It's not really input_as_int either. It's more like user_query_as_int. Which is an oddly specific and yet complex object.

You also see a hint of the procedural creeping in there, with the first input and then the second input. And isn't this unavoidable? What if you now extend this program to also ask for the operation. Add, subtract, multiply, divide.

I don't know. Maybe I've not even begun to grasp what we're aiming at here.

yegor256 commented 7 years ago

@g4s8 @mdbs99 @g4s8 I still think that we may introduce a rule: "an object A can call method M only if M belongs to object B, which is encapsulated by A." Think about it. I feel that it will solve a lot of problems in OOP. Suggested a discussion in our Gitter channel: https://gitter.im/yegor256/elegantobjects?at=588c6f985309d6b3587a7df9

nqafield commented 7 years ago

@yegor256 As opposed to what? Do you mean you couldn't call methods on an object that has been passed in via a method? Only those passed in at construction, or created internally?

goqp commented 7 years ago

@yegor256 I considered this solution before and it won't solve any problems - in fact it will create an unworkable disaster. You are using messages like operation invocations. That is the problem. The issue you are concerned with, which is creating objects which are autonomous, can't be resolved in this matter. The heart of OOP, according to Kay, West, and EVERYONE who ever really did it, is communication between nodes in a network. That means passing messages between objects who are distinct, not vertically between sandwhich layers of a complex object.

maxinovi commented 7 years ago

What do you think about different aspect of literals: custom literals?

Shortly speaking, the idea is that semantics of custom literals (and probably built-in ones) is defined not by syntax, but by the style of literals. It also means that source code is not a plain text anymore, but since eolang is designed as a new language, maybe it's possible to apply unusual approaches?

The basis is the following: when a type is defined, a styled literal can be defined for the type. The same story as for built-in types and literals such as strings, bools or integers. Semantics of a literal is retrieved from its style. For example, strings do not require quotes to specify what chars a string consists of, and no escaping required.

Literals look like the following:

Styled literals

pchmielowski commented 7 years ago

Do you mean, that we should format code by choosing it's font, colour and style?!

maxinovi commented 7 years ago

@pchmielowski

Do you mean, that we should format code by choosing it's font, colour and style?!

Yes, why not? Of course, there are pros and cons of the such approach, but I think proper tools can solve them. Modern programming languages adhere the principle "more expressiveness by less code", and styling provides additional dimension to plain text for specifying more sense without cutting syntax elements (I mean traditional ways like shorter keywords or mnemonic symbols).

The styling is a consequence of more general question: what do you think if source code is not a plain text, but tree-like construction? Not so radical such as AST, but some intermediate hybrid tree with text elements.

Tools like static analyzers, editors or compilers use AST to work with code. Only humans need text presentation to write and read the code. Moreover, we do already use tree-like approach when indent blocks and scopes in the code. So, can we remove text at all? Or at least partially? This will avoid us from hollywars like TAB vs SPACES or 2 vs 4 CHARS, which are the result of exactly textual presentation of the code. This gives us more power in semantics (like custom literals). Performance of practical tools can also be improved: phase of parsing becomes less expensive or missing at all since code tree is already available.

So, the styling is a way to specify the type of a node and render this type to humans reading.

nqafield commented 7 years ago

@maxinovi I'm not sure I fully follow what you're talking about but it made me think of this: https://youtu.be/TS1lpKBMkgg?t=39m27s

Which I originally referenced here: https://github.com/yegor256/eo/issues/5

maxinovi commented 7 years ago

@pa9ey Yes, in general I agree with Paul's topic and his statement "I need a coherent set of tools for creating software", though in details and the reasons for the topic look different.

I'm going to join discussion in #5. Regarding this I have one question. I'm developing similar project for object-oriented modeling and tools, may I put a link to it as a comment in #5? Since you are collecting resources about language development.

nqafield commented 7 years ago

@maxinovi It's Yegor you'd have to ask. But I don't see why you shouldn't post it. No harm in us knowing what's out there. :) That issue's a little dormant though. Not sure what to do with it.

yegor256 commented 7 years ago

@maxinovi sure, post a link, if it's relevant

yegor256 commented 3 years ago

@g4s8 yes, in EO numbers and strings are objects. You can do this:

[n] > f
  5.add n

This will make 5 + n.