janet-lang / janet-lang.org

Website for janet
https://janet-lang.org
MIT License
90 stars 58 forks source link

Non-ideal discoverability of Janet divergences from other programming languages #197

Open fnaj77 opened 1 year ago

fnaj77 commented 1 year ago

Hi to all, this is more of a suggestion than a problem per se.

As a newcomer, I accidentally discovered some peculiar features of the Janet language that set it apart from other programming languages. I'm quite sure they are rock-solid choices made by experienced people, and I'm not going to criticize them or propose changes.

But I think it could be beneficial, at least for beginners like me, to have a section of the Janet documentation devoted to highlighting conventions in Janet that might be different from what one might expect from other, widely used, programming languages.

Just to give some examples, I'm thinking about -2 used to refer to the last item in an array/tuple[1] or the 0-based index for day and month only in os/date[2], and I don't know how many other cases of this kind may exist.

I know that all these behaviors are well and clearly specified in the relevant docstrings but, as I said, I think it could be beneficial for beginners to have them listed on a single page and not scattered all around the documentation.

To be more clear, I'm not advocating changes in language semantic and/or behavior, just more "prime time" in the documentation about these divergences from common practice. I'm thinking about something in the line of "Janet for pythonists/clojurists" or "Janet for C/C++ developer" etc.

Please, above all, take this as a constructive proposal, I do not want to criticize someone else's free time/contribution. Thank you.

[1] https://github.com/janet-lang/janet/issues/1219#issue-1800975106 [2] https://github.com/janet-lang/janet/issues/1214#issue-1793833312

tionis commented 1 year ago

The behaviour of the match operator for shorter tuples would also be relevant here. This is explained in janet.guide/control-flow at “This is terrible, and you will mess this up at some point”

fnaj77 commented 1 year ago

The behaviour of the match operator for shorter tuples would also be relevant here. This is explained in janet.guide/control-flow at “This is terrible, and you will mess this up at some point”

Hi @tionis, you're right, match macro is ... funny to use too :)

sogaiu commented 1 year ago

I think it would be convenient for users to be able to discover divergences (to adopt the terminology of the issue's title) and/or potential gotchas.

I'm not really sure how to do this well though.

A single list might be nice, though for some things, perhaps one would want to learn about individual items in context (e.g. there is an example of slicing with a negative index in an example of this section). I suppose there could be a list which is pointed at from specific sections (or a specific part of the list could be linked to).

Note though that for negative index use, this might lead to a fair bit of extra text spread across multiple sections. That might not be so great from a maintenance perspective if certain changes were to be made later.

I hope it's clear from the little examination above that it's not necessarily a no-brainer to do this kind of thing in a maintainable manner. That's not to say that things couldn't be improved, just that there may not be a single easy-to-execute approach. Still, perhaps a good idea will come about or individual items might be improved upon.

For the moment, may be this issue could collect some potential content -- though if it's distributed throughout the issue, it may become unwieldy to act upon items from a practical perspective....

uvtc commented 1 year ago

Ok, time to pop my head out for a moment! :) I've seen two of these elsewhere, and thought they were pretty useful (full disclosure, years ago I wrote a few of the ones for Ruby (though I expect they've been updated a bit since then)) :

The ones for Julia are more lumped together -- I think the ones for Ruby are more nicely organized. :)

sogaiu commented 1 year ago

@uvtc Thanks for sharing those, will be working on digesting them.


P.S. Good to hear from you -- been missing your presence!

uvtc commented 1 year ago

Aw, thanks, sogaiu!

sogaiu commented 1 year ago

Along the lines of improving the existing documentation for the case of providing some explanation of how negative indices work in Janet, I think this section is a candidate for an addition.

sogaiu commented 1 year ago

Looking at the Ruby and Julia resources I was reminded of this.

sogaiu commented 8 months ago

I'm not sure yet whether the following should count, but I'll note it for future reference...

The */slice functions all have an optional start argument. The docstring for string/slice is currently:

    (string/slice bytes &opt start end)

    Returns a substring from a byte sequence. The substring is from 
    index `start` inclusive to index `end`, exclusive. All indexing is 
    from 0. `start` and `end` can also be negative to indicate indexing 
    from the end of the string. Note that if `start` is negative it is 
    exclusive, and if `end` is negative it is inclusive, to allow a 
    full negative slice range.

For the non-negative value cases, start can range from 0 through the length (NOT limited to 1 less than the length -- this is not mentioned in the docstring) of the argument being sliced.

For example, if slicing something of length 1, start can be 0 or as shown below, 1:

$ janet
Janet 1.32.1-11d7af3f linux/x64/gcc - '(doc)' for help
repl:1:> (string/slice "a" 1)
""
repl:2:> (array/slice @["a"] 1)
@[]
repl:3:> (buffer/slice @"a" 1)
@""
repl:4:> (keyword/slice :a 1)
:
repl:5:> (tuple/slice ["a"] 1)
()
repl:6:> (type (symbol/slice 'a 1))
:symbol
repl:7:> (length (symbol/slice 'a 1))
0

This was unexpected to me [1], but thinking of the value of start as representing or pointing to a space or gap between elements made it less odd, e.g. for a string:

byte position:  0 1 2 3 4 5 6 7 8
----------------------------------
       string:  ( d e f   a   1 )
      indeces: 0 1 2 3 4 5 6 7 8 9

In the case of a string of length 1, that might look like:

byte position:  0
------------------
       string:  x
      indeces: 0 1

I'll note that this may not be a divergence from other programming languages, possibly it might be considered a gotcha (but may be not).


[1] On a side note, it looks like one may produce a symbol of length 0:

repl:6:> (type (symbol/slice 'a 1))
:symbol
repl:7:> (length (symbol/slice 'a 1))
0

That seems a bit odd to me. Not sure if that's problematic...