Does anyone else wish that DrRacket indented this: (some-function
(expression1 ...)
(expression2 ...)
(expression3 ...))
like this: (some-function
(expression1 ...)
(expression2 ...)
(expression3 ...))
Why 3 spaces? (Or however many spaces you typed there?)
Do you mean; tab, 4 characters, or aligned to the ‘-‘.?
I agree it looks easier to read
I don’t see why
4 spaces (no tabs). My thinking: 1. 2 spaces for indenting nested blocks (things with internal definition contexts) 2. 4 spaces for indenting nested expressions
@mark.warren hard to tell what the structure is when code is indented like this: (some-function
(some-other-function
(another-function ...)
(yet-another-function ...))
(another-function ...)
(you-guessed-it-another-function ...))
Is it?
yes, in my experience, especially when lots of code like that is mixed with nested let
s and when the function arguments themselves take multiple lines
I agree that 1 space only not enough, but I’m okay with 2 spaces in all cases. Syntax color does the rest to distinguish what kind of block this is
4 spaces means you will drift much faster to the right
2 spaces has always been my preference
it goes to the right way slower than the usual racket approach does: (some-function (some-other-function (another-function ...)
(yet-another-function ...))
(another-function ...)
(you-guessed-it-another-function ...))
and I’m kind of alright with expression nesting going rightwards faster than block nesting does, since deeply nested expressions are harder to understand IMO (because fewer variable names and they can be nested in arbitrary ways rather than the relatively limited ways blocks are typically nested)
if an expression I’m writing gets complicated the first thing I usually do is name some subexpressions and extract them into definitions
To be fair, the code you have shown above probably should really be rewritten as:
(some-function
(some-other-function
(another-function ...)
(yet-another-function ...))
(another-function ...)
(you-guessed-it-another-function ...))
I hope this doesn’t sound abusive, but I tend to find if there is too much indentation then a function needs splitting up.
and with 2 spaces: (some-function
(some-other-function
(another-function ...)
(yet-another-function ...))
(another-function ...)
(you-guessed-it-another-function ...))
Looks good to me
no I think that’s a totally reasonable statement, I just think there’s more ways to split things up than into separate functions. splitting up one expression into an expression and some definitions is a handy way to split things too.
My hobby: Nesting for/fold
in #:result
s
Aside/ I like the idea of tabs - I recently read an article that argues they were better for the sight impaired as they allowed adjusting indentation at high magnifications. I don’t know if this is true? And in any case if you can adjust the reformat indentation you can get the same outcome with spaces
Yeah, Racket should be more like makefiles :stuck_out_tongue:
Tabs do have some useful accessibility features yeah. You can definitely get the same thing with spaces though as long as you aren’t using horizontal alignment.
I totally agree with @notjack on this one. The usual argument that people advocate for tab is that you can change tab size to fit reader’s need. But with a formatter, you can do the same with spaces.
It does require you to have more domain knowledge about the language.
Tabs could be useful for alignement after the initial spaces, i.e.: <space>*[:code:]+\tab[:code:]+\tab[:code:] would tell that the next lines should indent on the tabs after the first code
I’m a Java programmer by day and the tabs vs spaces argument is constant, as well as the indentation and bracket placement.
I’m one too and luckily do not have to have that argument at all anymore
Not everyone works at Google lol
@notjack hand over your webpages about all these to @mark.warren, they are nice rules
the rectangle rule one?
in particular, but the rest too
(for java I mean)
It was more about the sight impaired. Tabs are verboten in DrRacket
struggling to think of what the others would be
Style guide 6.3
Can’t recall just now, but there are other pages
Oh yeah, variable naming and such
anyway this is the rectangle rule, it’s part of what google-java-format
uses to figure out what formatting makes sense https://github.com/google/google-java-format/wiki/The-Rectangle-Rule
There is a quickscript that does that! (With spaces)
Hmm.. I just wish I could open a source file from someone else and it actually was readable.
hehe, yes, but I used double spaces because it’s complicated to type tabs in DrRacket :wink:
My hypothesis is that with tabs, you will find that more source files will be unreadable
the other useful guidance that formatter follows is “prefer to line-break at the highest level of syntactic nesting”, so instead of this: (some-function (some-other-function
(another-function ...)))
it would do this: (some-function
(some-other-function (another-function ...)))
I think indentation should require that every odd character is a non-breaking space, and the rest are tabs
Is a double space a space that is as wide as two spaces but still a single character?
it’s just two spaces
big brain time
@notjack I had a look at that guide and it looks even more unreadable than some of my colleagues code :grin:
there’s a gui option if you want to choose a different separator
it is deliberately showcasing difficult-to-format code :p
but if everyone uses the same unreadable format, then suddenly it becomes readable :wink:
Someone please stop @laurent.orseau :rolling_on_the_floor_laughing:
there’s a lot more to readability than formatting. but it’s an easy-to-automate part, so.
It would be nice if your IDE formatted the code in your preferred way but saved it in a non-formatted way, does that make sense?
yes
although sometimes (rarely) I open my code files with nano
…
and I do like being able to read code in github with a browser
So saving it in a ‘standard’ way would be best
yes
I thought a tab in nano is 8 spaces?
Can it be adjusted?
That’s terrible
yeah, everyone knows 7 is ideal
lucky nano isn’t your preferred editor I suppose
indeed
I think the ELisp if
indentation is the weirdest.
@notjack nah, it’s just convenient when CRD breaks :wink:
what’s elisp if
look like?
(if nil
1
2)
wh
what
lol
(if if-false
test if-true)
?
It’s because the else
position can have multiple forms
chaotic neutral
(if nil
1
2
3)
well that’s
oh it’s because the else part is multi-expr
an approach, certainly
my my
How about: (if test
e1
...
#:else
e3
...)
When I have a block in the if-true I often write ; else
anyway
y’know. cond
lets you write else
without it being a comment :p
or do you mean in elisp specifically
(if test
(filter (...)
auieauie)
; else
...)
even for one-expr cases
I’m not an unconditional fan of cond either
unnecessary parentheses
guard
? :wink:
if #:else
? :p
if #:ELSE
(if ... fi:# #:ELSE ... esle)
?
(consistency is hard!)
(if … #:ELSE … esle … fi)
yah, that’s the one
With nice error messages: missing esle in fi counterpart (also: missing fi in esle counterpart)
call them categorical duals instead of counterparts, to really get the angry blog posts flowing
good idea: missing esle in fi categorical dual (also: missing fi in esle outer disjunction)
Did you mean: 'printf' instead of 'if'?
If we have a form that enumerates all bound identifiers at a position, we could write #%top
that finds the closest id (via edit distance) and generates Did you mean: ...
.
namespace-mapped-symbols?
That’s only for top-level symbols
Doesn’t include local binding
that’s a start
for this you can use read-syntax after the fact
or even just (remove-duplicates (filter symbol? (flatten (read))) eq?)
@notjack IIUC one Lisp tradition is that there’s a distinction between function application and macro invocation.
Indentation for plain old function application is always the same style (that you dislike).
Whereas macros can define custom indentation.
I think this roughly maps to your 1 and 2 but I’m not sure?
I think there’s some value to letting macros define their indentation? Like say if
or for/fold
.
In some Lisps there’s a way for a macro’s indent metadata to be available for editors.
In Emacs Lisp I think it’s via the declare
form, but I try really really really hard to avoid writing macros in Emacs Lisp. :slightly_smiling_face:
I’m not sure how I would go about transforming the mpi’s into that form, though.
Hm, I might give that a look. I have limited control; students submit a file (ostensibly beginning with #lang racket
) which I dynamic-require
to get certain vars (reasons). If require transformers need me to actually adjust the student code, that probably won’t work.
In other Lisps, users need to set this in their editor. Which is the case for Racket. Things like DrRacket and Racket Mode just come with a set of defaults for common macro forms. Which you can customize.
Racket could probably have a better story for this (for macros telling tools their indent).
TL;DR I think there are team and tool challenges to changing the indent style for plain old function application, but if people want to configure that, it’s a possibility. OTOH I think there’s some value to letting macros have the last word for how they get indented, or at least a strong suggestion.
If I understood that write, if I could change require
to use my require-transformer
, I could do… something… My use-case is just to collect all the things being required. sigh back to the drawing board.
Yes. require transformers needs to be added to the code. If you don’t have control over the code, like #lang your-own-lang
, what I have in mind is a hack is to modify the submitted code from: #lang racket
....
to: #lang racket
+ (require your-library)
....
where your-library shadows the require
form and the module
, module*
, module+
forms: ;; your-library
#lang racket
(provide (rename-out [my-require require]))
;; my-require transforms (require <req-spec> ...) to (require (record-import-path <req-spec> ...))
then record-import-path
is a require transformers saving the import paths.
I don’t understand what happens to the module path index of submodules. A guess is that resolving the module path index turns it into the module path of its enclosing module, therefore module->imports
returns the same list
@greg, If I kill 50+ racket buffers with racket-mode and racket-xp-mode on, is the memory footprint of the backend server expected to drop down?
Hm, that’s pretty clever. (Of course, I have to figure out how to record-import-path
in such a way that I can get to it again later :thinking_face: )
Why shadow module/module*/module+? To insert the (require my-hack)
again?
Alternatively, if getting the list of all transitively required modules instead of just the immediately required ones also work for you, then intercepting current-load/use-compiled
is yet a different hook. https://gist.github.com/shhyou/726d0542aef45b13981173a334a0202c
Yes. Without shadowing module
, module*
, and module+
, requires that indirectly goes through submodules won’t be tracked
If ensuring safety is your goal, sandbox is also a good tool. https://docs.racket-lang.org/reference/Sandboxed_Evaluation.html?q=sandbox#%28def._%28%28lib._racket%2Fsandbox..rkt%29._make-module-evaluator%29%29\|https://docs.racket-lang.org/reference/Sandboxed_Evaluation.html?q=sandbox#%28def._%28%28lib._racket%2Fsandbox[…]rkt%29._make-module-evaluator%29%29
Yeah, we’ve used sandboxes before. I’m hoping to avoid that here; it would require some infra changes I don’t want to deal with. I’ll take a look at that gist, thanks.
I expect yes if you have yesterday’s commit https://github.com/greghendershott/racket-mode/commit/3e63bdc5bdc5a9d0a28f3568fa994a5792c447c5
Do you have that yet?
Keeping in mind that, after a major GC, Racket doesn’t necessarily immediately release memory back to the OS, if you’re looking at ps
or htop
etc.
But also, with that commit, I expect the footprint would not grow nearly so large in the first place.
I was testing by opening a few dozen files in the typed-racket-more
source, and I definitely improved that scenario.
But of course I don’t know for sure if you’re exercising something else that I don’t yet know about or understand.
@capfredf ^
> shu—hung [9:51 AM] > I don’t understand what happens to the module path index of submodules. (For this issue, people on the Racket mailing list may be able to offer help)
Oh, to clarify: As of that commit, I wouldn’t expect killing the buffers, per se, to release memory. Instead I’d expect it to have been released long before that. Merely having the buffer open isn’t any kind of strong reference. Instead it’s the act of invoking check-syntax by e.g. editing a buffer, or other commands that need fully-expanded syntax.
A buffer just sitting there, existing, isn’t doing that. so killing it won’t change anything.
Issue 512 involved quite some detective work, I see!
Ah I see. Thank you for the hard work
@capfredf Thanks for the thanks! Even so, with that commit, if you still see memory use that seems excessive, please don’t hesitate to let me know.
I think it’s worth trying out 2 spaces in actual code and see how it looks. What I fear is that it could cause confusion with existing forms that have 2 spaces indentation.
(lambda (foo)
abc)
(something
bar)
Also, two spaces from where? It should already be taken for granted that inner forms must be indented by at least one space to align with the left parenthesis. So when you said two spaces, should it actually be three?
Are there any tutorials on how to write embedded DSL syntax different from S-expressions?
Beautiful Racket talks about this
I mean, an embedded SDL with syntax different from S-expression which can still be embeded into a S-expression language, let’s say Racket.
I mean one more space, like your example above
Different syntax in different files or in the same file?
If the former, do look at Beautiful Racket
If the latter, do that anyway and you’ll also need to change the reader locally (don’t recall what the name is right now)