profile for monkeydom at Stack Overflow, Q&A for professional and enthusiast programmers

cocoa-dom

coding bits I use, come across, like, hate, the whole shebang.

twitter | github      rant-dom         rss | archive

Command line utilities: exa and bat

While surfing through the rust ecosystem, I stumbled across a few excellent command line utilities I enjoy using and installed on all my systems. I'm going to post about them for my own reference and in case they might be useful to you too.

exa

exa is a modern replacement for ls. Apart from great coloring I use it mostly for its tree based view and git and extended attributes integration.

dom@dreizehn:/usr/local/etc$ exa -lTF
drwxrwxr-x     - dom  3 Jul 13:02 ./
drwxr-xr-x     - dom  3 Jul 13:02 ├── bash_completion.d/
lrwxr-xr-x    36 dom 29 Jun  2017 │  ├── brew -> ../../Homebrew/completions/bash/brew
lrwxr-xr-x    48 dom  5 Oct  2017 │  ├── exa -> ../../Cellar/exa/0.8.0/etc/bash_completion.d/exa
lrwxr-xr-x    51 dom 29 Apr  4:36 │  ├── fd.bash -> ../../Cellar/fd/7.0.0/etc/bash_completion.d/fd.bash
lrwxr-xr-x    65 dom 22 Jun 16:38 │  ├── git-completion.bash -> ../../Cellar/git/2.18.0/etc/bash_completion.d/git-completion.bash
lrwxr-xr-x    59 dom 22 Jun 16:38 │  ├── git-prompt.sh -> ../../Cellar/git/2.18.0/etc/bash_completion.d/git-prompt.sh
…

bat

bat to me is a great less/cat combination that adds syntax highlighting and line numbers. Especially useful on remote servers.

dom@dreizehn:/etc$ bat hosts
───────┬────────────────────────────────────────────────────────────────────────────────────────────
       │ File: hosts
───────┼────────────────────────────────────────────────────────────────────────────────────────────
   1   │ ##
   2   │ # Host Database
   3   │ #
   4   │ # localhost is used to configure the loopback interface
   5   │ # when the system is booting.  Do not change this entry.
   6   │ ##
   7   │ 127.0.0.1       localhost
   8   │ 255.255.255.255 broadcasthost
   9   │ ::1             localhost
───────┴────────────────────────────────────────────────────────────────────────────────────────────

Swift Library naming warts

This is just a collection of oddities / naming choices that I ran across while playing with Swift. This list isn't exhaustive, nor do I have a good solution for all of them. It's just an observational piece on things that produced a negative gut reaction.

  • the func keyword
    somehow that one really doesn't sit well with me. I'd much more preferred it if the keyword would have called function. However It has been pointed out that other abbreviations are used as well in standard keywords. Most notably: enum, var
  • succ(), pred()
    The ForwardIndex and BidirectionalIndex use these methods to move forward and backward. I'd much rather have seen successor() and predecessor() there. Or nextIndex() and previousIndex() since these methods are tied to Indexes. Or succedingIndex() and precedingIndex(). Actually this hits a sore point in the current Swift Library quite on the mark: how general or specific should the naming of methods and global functions be? And how can this be as consistent as possible to give future code writers the right idea and direction to make these in a way they fit in the language? Something that is very established in Cocoa and imho needs to be established in Swift as soon as possible.

  • advance()
    This is used to move an index forward by a distance. So why not advanceIndex()? And also what is the inverse? I found no good one in the english language, but I'm foreign. There is no inverse because you are supposed to use advance with a negative distance to move backward. I like that the name includes the direction, so you know your moving forwards with a positive distance and backwards with a negative index. However, I don't like the impetus of advance, suggesting to me going forward is the only way. 
    Interestingly enough it hits another point: mutability. Does advance() change the index given or not? This is not clear by the naming, but I think it should be.

  • join(a,b) and <Type>.join(b)
    These behave consistent but are confusing to me as hell. Compared to cocoa's [NSArray componentsJoinedByString:] which is clear to me. So to join ["c","d","e"] with "-" as glue you have to do either join("-",["c","d","e"]) or "-".join(["c","d","e"]). I think the more intuitive version would be something like ["c","d","e"].joinBy("-") - I also don't get exactly why it is both a global function and a method. I would prefer the function to be defined as join(a, by: b) with the semantics reversed. Everything would be much clearer and visible to the first time reader at a glance. However, the swift library does not make use of named parameters on a function level.

  • Array.append(), Array.extend(), Array.filter(), Array.sort()
    This again hits my sore spot on mutablity. Which of these methods return a new, changed array, which do mutate the array? Without consulting the documentation or Xcode there isn't a clear indication. It turns out sort() sorts in place while filter() returns a filtered array. We need a consistent way of expressing this in the naming.

  • contains(a,b)
    Does this test if a contains b, or if a is contained in b? You can't be sure without looking at the signature. I would much rather prefer this to be something like does(a, contain: b). and for it's brethren with the predicate doesAnyElementOf(a, satisfyPredicate: b). However, with trailing closures being able to lose the last parameter name and just putting the closure at the end that might look awkward. But I sure as hell don't get why one should name basic functions in a short way, if there is a possible improvement in readability and less ambiguity by writing a longer signature.

Autolayout and Complexity

I recently dipped my toes into some autolayout on both iOS and OS X. Short term verdict: powerful, but too complex for daily use. And that's an issue.

Remember the times of handling touches before there were UIGestureRecognizers? That is exactly the state autolayout is in. The underlying technology is great but it is in desperate need of a good abstraction layer on top of it that makes the standard use cases easy and maintainable. I'm looking forward to this year's WWDC to see some of these aspects to be addressed.

Blocks need considering

While I don't agree with this post in most respects, it still alerted me to a crucial thing when using blocks: Be sure the Macros you use in them don't reference self directly. And if they do and you need to be sure to not create a retain cycle, use either @weakify and @strongify from libextobjc or do shadow self yourself this way:

__weak typeof(self) weakSelf = self; 

// some api that takes blocks, when you give the block do 
^{
    __strong typeof(weakSelf) self = weakSelf; 
}

So thanks for ranting so much to alert me to the fact that NSAssert() does reference self directly, and as such make the block retain self.

Update: ZAssert seems to be a reasonable replacement for NSAssert() in blocks which is mentioned in the comments of the Article.

Update 2: Since this is such a common pattern, I've seen people using welf instead of weakSelf, which makes me chuckle. Also the __typeof__ can be replaced by typeof, which makes it less atrocious.