Web design like that makes it take so long to figure out what the language is actually about. It’s like a flashy, hard-to-navigate slide show (not to mention laggy scrolling even on my desktop).
Contrast with Rust’s homepage, which actually gives you a fair chance of figuring it out in just a couple minutes.
If the only good thing about vim is the user interface, why not try Emacs with evil-mode? I made the switch recently and I’m enjoying it: the vim bindings are very, very complete, and you have an incredibly scriptable environment to work in.
I’ve been considering making this switch for a while now, but the main thing stopping me has been the fact that while evil-mode might duplicate the vim interface, it won’t duplicate all my vim plugins (I use a handful of custom text objects and ‘verbs’ quite often). So I’m really excited about the idea of a better vim that still has plugin compatibility.
Do you need your vim plugins as they are? Considering the number of Emacs packages, you could probably find something that provides more-or-less the same functionality. As for custom text objects, I have seen a couple in the MELPA package archive, and if those don’t do, you could embark in an Elisp hacking adventure.
This is true. In fact, it might be easier to write these plugins for evil-mode than it was for the original authors to write them in vimscript, depending on how evil-mode plugins work. On the other hand, it’s always going to be easier for me to just do nothing, and having to find or reimplement plugins doesn’t help me overcome my inertia. Still, it might happen one day, but I think the prospect of neovim is only increasing my vim inertia.
How do others feel about the default format for
jj log
? To me, it seems cluttered and hard to parse at a glance, but I like that it tries to display a tree. More spacing would probably help me, but maybe you get used to it?I basically have been using that format forever but with tutti-frutti colours.
https://pasteboard.co/ErkB66UitzN6.png
Still waiting to see if it clicks, as-is; definitely share your views on it, but I figure it’s not an accident and am curious to see how much more natural it gets. That said, I ended up having to override
git log
’s defaults a lot, too, so who knows.There’s an alternative default that I find quite nice with more spacing. This is the config:
The reason the reference doesn’t know this is because it’s false. You can see it if you make it a
&mut
, assign to it, and printarr
- it will be unchanged. Theif
expression produces a by-value temporary i32, and you can take a ref to a temporary as a convenience, which will place it into a hidden variable and then ref that variable.Yep, I came here to say this. Another way to test the hypothesis is to use the supposed place expression as an assignment target: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9aa624e4e3bc05e63c1ccb370175f6a6
I don’t actually really understand the claim the author is trying to make. It’s it just that they’re surprised that the syntax works?
yeah i figured that out..
Why would everyone ever want to know? Isnt this why inttypes.h exists? Is int8_t and uint8_t not more clear?
The problem is that all arithmetic gets promoted to int, using explicitly sized types doesn’t make any difference.
Although in that case, since
int
has to be at least 16-bits per the standard,uint8_t + uint8_t
must always call theint
overload (because it always fits), never theunsigned int
overload. On the other hand, whilechar
can do weird things like be as large asint
(as described in the post),uint8_t
can simply not exist if the implementation doesn’t support it.Because you have two overloaded functions, one that takes a char as an input and one that takes an integer as input.
They have different behaviour, then you need to know which one will resolve :-)
Cool! I wonder what happens if two adjacent bots drill-move through each other or if two nearby bots both move or both drill-move to the same location.
I think their turns are all taken separately, so one event will always happen before the other.
Well, I was gonna do some other stuff, but instead I’m having my imposter syndrome triggered by this thread.
Here, let me help you out:
I’m doing nothing interesting this week, which is why I haven’t responded to the top-level comment.
edit: Huh, “troll”? I think it’s entirely reasonable to let other people know that not everyone is doing something interesting. I’m not being sarcastic or mean-spirited. Sometimes we are just boring and that’s ok.
Does sound rather passive-aggressive.
I really don’t understand. In fact, I’m thoroughly confused. I have not responded to the top-level request for what am I doing this week, because I am not doing anything. Nothing to say, so I stay silent. What are people thinking that I mean? How are people thinking I am being aggressive?
I think the assumption is that you were implying that corbyhaas shouldn’t have replied to the top-level comment either.
Ohhhhhhh, crap. That’s not what I meant at all. I was meaning to say, “it’s ok, lots of people aren’t doing interesting things, you are not alone, but you won’t hear about people not doing interesting things because they won’t say anything.” I was trying to indicate that only the loudest people would be talking in this thread, and that there are lots of silent people who just were not as exciting right now. It is perfectly ok to be merely adequate once in a while, or all the time.
This is one of the coolest things to have in the standard documentation, IMO. Rust claims to be good for replacing C/C++ where other languages can’t and shows you in detail how it could be done in a semi-realistic example.
This is how I feel about it, too. Once you understand ownership and borrowing well enough, it doesn’t make you jump through hoops to do things the way you’d do them in higher-level languages.
Thanks! I had the embedding idea right before 1.0, and in retrospect, I’m really glad I did.
Hm, I’m not sure - for me, it feels very much like one. What I love about Rust though is that it doesn’t take the route of “You have to know all these things and things break if you don’t!”, but encodes many of them.
For example, many things are possible when you know the size of the type at hand and some are not if you don’t. Rust makes that very explicit: using the
Sized
trait. Coming (back[1]) from dynamic languages, that helped me a lot. It gave me enough info to start thinking about this issue and helped me form my mental model again.Not exactly on topic but am I the only one finding the screenshot blurry? I’d be guaranteed a migraine working with display like this for more than a few minutes.
It’s being scaled down by your browser. Try the full size image.
I’m not so keen on some of these ligatures. The
#
ones in particular seem a bit poorly designed. But I hope more people try to make ligature fonts and more people try to get editor support working (emacs and vim being notable unsupported editors). I think this could be done really well eventually, so I applaud any effort in that direction.I’ve tried another ligature code font, Hasklig, and it’s great, though obviously Haskell-centric, and it’s not supported in my main editor right now.
I’m glad people are experimenting here, since notation is so fundamental to thought.
To your note about vim support: I am a bit concerned about two things:
1) Rectangular selections 2) Character-oriented motions
I’m concerned about what happens when your selection or cursor cuts a ligature; or when you want to move to the all or part of the ligature’s character sequence. As an example of the latter, consider the <= and >= operators. The ligatures give no hint that the equal sign is the second character, so how do I know what happens if i type
f=
ort>
to move to a ligature? It may or may not be confusing, but I’m sure that there are many more subtle issues to consider, so, again, I’m glad people are experimenting here.Thanks for bringing up those points.
I’m not sure what’s the best way to handle half-selected ligatures, but my first thought would be to temporary undo the ligature to show the raw characters (kind of like how vim’s conceal feature works). Or you could just leave the ligature as-is and make the programmer infer what’s actually going on. They should know what their ligatures actually stand for regardless.
I never thought about the effect on commands like
f=
andt>
before, but again I think it would be reasonable to assume the programmer should just know that ≥ means>=
. You would lose on the quick eye scanning and spotting a=
to jump to, though, so that’s something to consider.And +1 to experimenting with notation. I see ligatures as one of the easiest ways we can go beyond ASCII without really leaving ASCII. In comparison, adding unicode to programming languages usually gets shot down a lot faster, which is fair since it’s a lot more problematic.
I also only read the deck and completely agree, this is a superbly useful introduction to using
Either
.I’m a little sad that he papers over exception handling by saying “just don’t use exceptions”. Is it just common knowledge that you shouldn’t use exceptions in FP, and if so is there another article I might read, or is there a different way of handling them nicely that just doesn’t fit into this framework?
You can handle exception-throwing code by using a try/catch that gives you either a Success or a Failure wrapping the exception. This is the approach
std::expected<T>
in the C++ Library Fundamentals TS is going to take. It’s basicallyResult<T, std::exception_ptr>
.Of course, this forces you to do the wrapping (at least semi-)manually.
I’d love to see examples of your Ruby use, do you have any you can share?
I have been experimenting with OO design (along the line of Bernhardt’s “Boundaries”) and pulling in FP concepts to a Ruby web app.
Almost all of the raises are in immutable values that raise if something tries to construct them in an immutable state, but the only rescues are in the outermost layers. They catch exceptions only to recognize when users have invalid input.
The handful of raises in the mutable entities are asserts to catch known, specific regressions. None are caught.
Some services (I don’t love the name - objects here have side effects but little or no state, suggestions welcome) raise for assertions and one piece of flow control to the calling service (happens only after 16k invocations and enables a Tell, Don’t Ask encapsulation).
There’s only one place where I commonly use an exception for flow control: if a database fetch fails I raise rather than return nil. A few places catch this to 404 the user, and two create an appropriate new object (eg. the lookup was a cache miss). Yes, a Maybe monad is the Right Answer but this app is already a step away from idiomatic Ruby.
This codebase is not yet public, but fingers crossed the RailsConf talk proposal I’m submitting is accepted and I present it there.
There’s a smaller example of this strategy in my new gem TwoFactorAuth. I only have one raise in a value/model (
app/models/two_factor_auth/client_data.rb
). I’m at the end of a long day so I can’t remember clearly, but I think this is an oversight and can be replaced with the appropriate ActiveModel::Validation. The rest of the raises are all assertions that the developer has configured the gem correctly at startup time; there are some heinous gotchas in implementing U2F.This gem does not use the value/entity split of the previous project because it is all about validating random, possibly hostile user input and debugging would be insane if you could only see one error at a time.
ActiveModel::Validations
is a nice fit for a gem that will almost always be used with Rails. Because of that I decided that “Railyway Oriented Programming”, though attractive, would be a huge step away from idiomatic Ruby/Rails for little benefit.Hope these notes on my experiements and the thought process behind them helps. :)
I only read the slide deck, but this is an excellent presentation of
Either
/Result
-based error handling. Very useful for users of any language that takes a functional approach to error handling, e.g. Rust which uses the same model that is presented here.It is such a relief to see this. Making the system usable was the biggest challenge.
While the preceding comment confirms Rust does not exceed the pain threshold of all programmers, this is probably still true. It is also my biggest worry about Rust adoption.
This is where I’m at. I was a die-hard C++ programmer for a long time. Yet Rust seems totally unapproachable to me. I’ve moved on to Python and Go; it seems the problems I solve these days aren’t incompatible with garbage collection.
I’d be interested in hearing why you feel it’s unapproachable, if you don’t mind elaborating. You said you’ve were doing C++ for a long time, so I’m guessing it was all pre-C++11?
I have to think about it more, but it starts with the new operators in Rust:
As a newbie these might as well be on an APL keyboard. With a history of using C, C++ (before C++11), or Java, none are obvious except for & and maybe mut. I realize some of these have changed in newer versions of the language, but this is my impression of it.
Most of the magical memory management and pointer types I’ve used in C++ are variations on templates like shared_ptr<> or unique_ptr<> or linked_ptr<>. Instead of special symbols or syntax it’s just plain old names. These are readable and discoverable to a new reader of the code.
Python and Go are also pretty simple in the operators they use. The worst Python has is probably
*
and**
for function arguments. Go’s worst is<-
for channel operations. I realize that Rust is trying to do something different and needs more ways to express that, so I’m not putting it down here.If it’s worth anything, another data point is I’m not in favor of Python adopting the @ operator for matrix multiplication (PEP 465). I think it’s too hard for newbies to quickly understand what it means.
While it doesn’t invalidate your reasoning, you are going off slightly out of date information. Actually, I think the Rust community came around to the same opinion you expressed here and decided to change the language. For example,
~
and@
haven’t existed for a while now. Just like C++, instead of special symbols or syntax, Rust decided to go with plain old names.For the pointer types, as a quick approximation,
&T
isconst T&
and&mut T
isT&
, but they give you stronger guarantees than C++ is able to provide: for example,&T
pointers can be relied on by the optimizer to never mutate, unlikeconst
pointers and references in C++.&'a
(lifetime specifiers) andref
/ref mut
(used in pattern matching) are admittedly fairly confusing for newcomers. There have been some improvements lately which allow you to omit lifetime specifiers in a lot of cases, which helps.If you’re still interested in Rust, I would encourage you to check it out after 1.0.0 stable comes out in a few months. You may find it has become a lot more approachable.
Cool will do. I guess first impressions are hard to shake.
Thank you for elaborating. I think /u/tsion said what I was already going to say :)
We need another suffix. “Considered Harmful” is too overused.
Considered harmful considered harmful?
http://meyerweb.com/eric/comment/chech.html
How are you handling algebraic data types in Ruby?
The standard OO approach for modelling ADTs would be the Visitor pattern.