nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.55k stars 1.47k forks source link

Remove default implementation of `$` for objects #8023

Closed ghost closed 6 years ago

ghost commented 6 years ago

It causes more headaches than implementing $ for our objects ourselves.

andreaferretti commented 6 years ago

What are the reasons behind it? I find a quite fundamental part of the language - just look at OCaml for a language that does not have this feature and triggers never ending requests for it!

Doing this would make life harder for every beginner out there and cause a bad first impression. Please, do not remove it!

data-man commented 6 years ago

@nc-x Instead of removing, you can help improve it.

dom96 commented 6 years ago

Also against the removal of this. I outlined my reasons on IRC: https://irclogs.nim-lang.org/12-06-2018.html#14:07:47

ghost commented 6 years ago

Doing this would make life harder for every beginner out there

Well I am certainly a beginner and having a default $ for objects did make my life harder

What are the reasons behind it?

The reason is that when you have a single file in which you have an object and you use $ in that file, everything works ok. But now if you try to use $ in another file, all the values are printed as ... because they are not exported. And then you waste hours trying to find out why are you getting ... and in the end you either unneccessarily export all fields or you have your own little $.

After wasting time on this exact same case, IMO i would prefer not to have a default $ for objects and have the compiler give an error when trying to print an object so that without wasting time I can create my own $.

and cause a bad first impression.

No it won't. Rust has a clear difference between Display and Debug and it is pretty much liked by everyone in the community.

In Nim, we also get the same kind of distinction with $ vs repr.

The proposal is to remove default $ for objects but improve repr for more use cases.

Araq commented 6 years ago

I've hit the bug twice now that my own $ failed to be imported and the compiler used system.$ instead which is wrong. This is just too error prone and should be done explicitly via implementToString(MyType) where implementToString is a simple template in system.

GULPF commented 6 years ago

This is just too error prone and should be done explicitly via implementToString(MyType) where implementToString is a simple template in system.

IMO that is the wrong solution, since the point of the default $ is to make debugging easier. Adding implementToString to every type you want to debug is horrible.

It would be better to change repr into something that is actually useful (most importantly, it needs to handle collection types somehow), and maybe introduce a separate echo that uses repr instead of $.

andreaferretti commented 6 years ago

I think it would be easier to warn novices in the manual about the reason why ... can appear when printing an object.

At the very, very, very least, there should be some macro that implements what we have today, so that people who want to keep this behaviour just need to from sugar import printObjects

zah commented 6 years ago

The introduction of new proc like dbg that can print a more complete and accurate data might be the right solution. It can also support output in some machine-readable format such as JSON that certain debuggers might be able to display in even better way (as expandable tree of items, with embedded HTML or graphical fragments, etc).

ghost commented 6 years ago

the point of the default $ is to make debugging easier.

$ is meant for converting to a string, not for debugging. repr is meant for debugging and should be improved if it does not fulfill its requirements.

I think it would be easier to warn novices in the manual about the reason why ... can appear when printing an object.

Yeah, it would be a 1 line change. But how many people do you think are going to remember it? Also, how many people do you think read the manual line to line?

from sugar import printObjects

Why is this any better than echo obj.repr (if repr is improved) or implementToString(obj)? Just because you have to type .repr or implementToString for every object does not provide enough reasoning for this import IMO.

GULPF commented 6 years ago

$ is meant for converting to a string, not for debugging. repr is meant for debugging and should be improved if it does not fulfill its requirements.

What I mean is that the only use case for system.$ for objects is debugging (at least I can't image any other use case). If it's removed, that use case must be covered some other way. An improved repr covers the use case, but implementToString does not. I agree that it's useful to have separate procs for debug and stringify, so I agree that system.$ for objects should be removed.

Araq commented 6 years ago

It would be better to change repr into something that is actually useful (most importantly, it needs to handle collection types somehow), and maybe introduce a separate echo that uses repr instead of $.

Yes, good, I like this proposal better than my own.

andreaferretti commented 6 years ago

No matter whether one points users to repr, people will just try echo myObj. This should work and produce something reasonable.

The current behaviour works, is convenient, can be easily overriden by implementing $ for some particular object, and apparently has the only downside that fields that are not exported appear as .... I really fail to see a problem.

If ... is so mysterious, just change it to <private> so that the reason for not seeing a value would be clear

andreaferretti commented 6 years ago

how many people do you think read the manual line to line?

not many, but people who have some issue printing objects would find this note.

With the proposal to force users to use repr - how many users would find about it?

ghost commented 6 years ago

not many, but people who have some issue printing objects would find this note.

Unfortunately, no one has enough time or interest in searching for a needle in a haystack. This is reason for the "We want better compiler error messages" movement in this decade which Elm, Rust, etc. are trying to follow as well as pioneer.

With the proposal to force users to use repr - how many users would find about it?

If the user tries to echo myObj and the compiler shows message

$ is not defined for myObj
implement $ for myObj, or use myObj.repr

I would say anyone and everyone would be able to find it with ease.

slangmgh commented 6 years ago

When I just want to write some code to try nim like this:

type
  Foo = object
    x: int
    f: float
    s: string

echo F()
echo F(x: 1, f: 1.0, s: "hello")

Now I have to write '$' proc, feel rather bad.

ghost commented 6 years ago

@slangmgh Yeah, but if you try to write echo F(x: 1, f: 1.0, s: "hello") in another nim file, all you are gonna get is a few .... To workaround it, you need to implement $ yourself or you would need to export all the fields to the objects, which means that you are just making the fields public which may lead to accidental value change.

And this behaviour, though easy, is certainly not intuitive or great.

This is the exact scenario being discussed here, and the alternative proposed is that, you could use echo F(x: 1, f: 1.0, s: "hello").repr to print the value if you don't want to implement $ yourself, or you go and implement $ yourself.

slangmgh commented 6 years ago

If we remove the default '$' for object, we need implement '$' not only when I access the object in another file, but also in the same file. An more clearer error message is enough.

dom96 commented 6 years ago

Having a $ for objects that works is very intuitive, it composes incredibly well with a $ for other types. I would argue that it should be extended to ref objects too.

repr should be improved, but it's use case is to look at the low-level details of objects. This is why when you repr an object with a Table field you will get a lot of "hidden" information about the Table object. This IS useful, and adding special cases for things like Table in repr is bad.

Araq commented 6 years ago

If ... is so mysterious, just change it to so that the reason for not seeing a value would be clear

That should be done in any case, yes.

dom96 commented 6 years ago

Looks like $ for ref objects was rejected here: https://github.com/nim-lang/Nim/issues/7890#issuecomment-392680367 :'(

dom96 commented 6 years ago

IMO the decision has been made: $ for objects should remain and we should add $ for even more generic things (ref types for example).

See https://github.com/nim-lang/Nim/issues/8149 for further discussion

kayabaNerve commented 6 years ago

I'd like to comment on this as I am having frustrations with this myself and I was late to the initial conversation. It sounds like people were against moving it to debug() and I can't follow the final statement about repr().

What if we didn't disable it but didn't force it on users? We could put it under a pragma. {.supplyDefault$.}

Having any user defined object supplied a $ operator is both a neat debugging tool but also an annoyance, especially if it sometimes overrides user supplies $s (unless that was fixed). That said, this also conflicts with Nim's design of having a strong static typing system and isn't intuitive. It's broken my code a few times now...

Can we AT LEAST have a command line/nimscript option to disable these? It's extremely annoying to have to declare `proc `$`(x: myType) {.error.} and if the default does override the user defined one in certain cases, it isn't even guaranteed to work.