REPL becomes irresponsive for some seconds if StyledStrings is loaded after OhMyREPL
Closed this issue · 13 comments
This is the issue:
- Add
OhMyREPL
andStyledStrings
- load
OhMyREPL
(using OhMyREPL
). - load
StyledStrings (
using StyledStrings`).
Result:
The REPL is returned normally after loading StyledStrings, but becomes irresponsive for some seconds. In my computer, about 10 seconds. In the example below, the multiple julia REPLs shown at the end appear because I typed "enter" multiple times without any response:
% julia --startup-file=no
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.10.4 (2024-06-04)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
(@v1.10) pkg> activate --temp
Activating new project at `/tmp/jl_n7Dg7r`
(jl_n7Dg7r) pkg> add OhMyREPL, StyledStrings
Resolving package versions...
Updating `/tmp/jl_n7Dg7r/Project.toml`
[5fb14364] + OhMyREPL v0.5.26
[f489334b] + StyledStrings v1.0.2
....
[83775a58] + Zlib_jll v1.2.13+1
[8e850ede] + nghttp2_jll v1.52.0+1
[3f19e933] + p7zip_jll v17.4.0+2
Info Packages marked with ⌅ have new versions available but compatibility constraints restrict them from upgrading. To see why use `status --outdated -m`
julia> using OhMyREPL
julia> import StyledStrings
julia>
julia>
julia>
julia>
julia>
julia>
julia>
The issue does not occur in Julia 1.11.
I think this is due to the type piracy in StyledStrings (cc @tecosaur)
I'd suspect so. To backport as much from the 1.11/StyledStrings behavior as possible, the compat "1.0" release of StyledStrings redefines the generic methods for join
and a few other widely-used/highly-invalidating functions.
Perhaps there's a better compromise to be struck between complete comparability and latency/invalidations? If so, I don't have much of an intuition about where to strike it.
X-refs: JuliaLang/StyledStrings.jl#57, JuliaLang/StyledStrings.jl#61
But why there's a lag after the recompilation apparently finished? Waiting for recompilation is, well, ok, but having an irresponsive REPL is another kind of issue.
Without doing testing + profiling: no idea on my end.
the compat "1.0" release of StyledStrings redefines the generic methods for join and a few other widely-used/highly-invalidating functions.
Oh boy... That's kind of awful. And 1.10 is an LTS so everyone who happens to start depending on StyledStrings will inject these latency mines for people using the LTS for a long time...
This is not an issue with this package, it should be opened in StyledStrings.
Oh boy... That's kind of awful. And 1.10 is an LTS so everyone who happens to start depending on StyledStrings will inject these latency mines into the code for a long time.
Yea, I don't want to have those "latency mines" as you call them either, but I'm having trouble seeing how they can be avoided without compromising backwards compatibility. As always, help would be appreciated.
You have to make the code so that it is generic and doesn't have to inject its special behavior into every Vararg{AbstractString}
function. Right now, AnnotatedString
has anointed itself as the "god string type" that is above everyone else which is why it has to do this overwriting so it can win against everyone else.
But this is completely unscalable and "anti Julian", what if someone else would want to do something similar? Whatever packages that got loaded last would "win" but this behavior would be wholly unpredictable.
It's not all Vararg{AbstractString}
functions that need to be overwritten, only ones that have blessed the String
type specifically (such as join
). This wasn't scalable to start with.
what if someone else would want to do something similar?
If we wanted join
to be generic in terms of supported output string types, it would need to be rewritten to be more generic. In Julia 1.10 and earlier it's specialised on String
, now it can produce String
and AnnotatedString{String}
, supporting any AbstractString
would be a separate step again.
To me it doesn't seem as though AnnotatedString
has "anointed itself as the 'god string type'" so much as tried to sit next to String
in some key cases.
To me it doesn't seem as though AnnotatedString has "anointed itself as the 'god string type'" so much as tried to sit next to String in some key cases.
It has because it wins vs all string types and the way it does it is via type piracy and method overwriting. And the generic join
method is documented to return a String
You might have the same argument about collect
providing Array
s but the solution then is not that everyone goes and overwrites collect
so that their AbstractArray
is returned if any of the argument is that. Then it should have a better API like JuliaLang/julia#36537.
A generic API that doesn't privilege the String
would be interesting, but I don't think I'm up for embarking on that project (or at the very least, not alone).
The fundamental problem here is that annotations are an incompatible extension of the concept of a string. It's similar to the famous "circle-ellipse problem" in OOP. So far an AbstractString
has meant "a sequence of code points". If that's all you know about, you can't handle annotations correctly. So the introduction of AnnotatedString
is really about adding that notion to AbstractString
, but it's implemented as a new subtype. That is never going to be fully natural, which is what leads to attempted solutions with things like type piracy etc.
The String
type is a default. When we're not sure what type to return, we pick that one. However that is ok, because String
is in fact able to accurately represent any AbstractString
, except maybe not efficiently. Introducing an incompatible extension of the concept means a new type needs to be the default, and code needs to be rewritten. That's the real problem here, not some general concern about whether any type ever gets to be "special".
There is obviously a lot of history of string types and algorithms, and people are familiar with them. So personally I don't think it's realistic to add the idea of annotations and expect everyone to be able to work with it. Strings are just too fundamental and popular to take on this new job. This is a really cool feature so it's unfortunate, but IMO it needs to remain an opt-in feature where annotations can only be preserved when you are careful about it, and AbstractString code can continue working only on codepoint sequences.
It's an interesting situation.
In conversation a while ago with Scott Jones about the type hierarchy and AnnotatedString
, and one thing I put forwards is that perhaps the conceptually purer way of doing things would be to have some AbstractX
supertype (perhaps AbstractText
? Strings are more than just textual though), of which AbstactString
and AnnotatedString
are both subtypes.
A consequence of this though would be that a lot of AbstractString
code would want to be replaced with AbstractX
. That's quite a lot of churn.
The way I see the compromise (I should probably PR an update to the AnnotatedString
docstring to make this clearer, I'll bundle this with some other docstring tweaks that seem sensible) is that AnnotatedString
introduces extra semantics compared to AbstactString
, but they're treated as deliberately fragile. Any time an AnnotatedString
is passed to a function that accepts an AbstractString
but doesn't want to think about annotations, those annotations just evaporate.
I think this goes some way to resolving the tension, but there are a bunch of basic functions (e.g. join
) where it's nice if annotations are preserved if present, and so I think worth doing so.
Perhaps I'm overly optimistic, but despite the complications I find myself encouraged by the improvements I'm seeing it enable/open the door to, things such as:
- With
JuliaSyntaxHighlighting
, pretty display ofExpr
objects in the REPL - With
JuliaSyntaxHighlighting
, highlighting of Julia code in docstrings/markdown - Potentially (PR inflight) avoiding a display bug in a PR to Profile where truncation is blindly applied to a string (currently) containing ANSI sequences
- Allowing emphasis/style in log printing (e.g.
@info styled"you did a {styled:bad}, but you probably want {success:good} instead"
) - The work I've just started on fancier error printing
- REPL Banner code that can be written just once for the color/nocolour case, with extra niceties like a link to the online
Pkg
docs (if that PR ever gets merged)
and I expect more to come with time.