[1+1=2]

OneAndOneIs2

Thu, May 16, 2013

[Icon][Icon]Quicksort golf

• Post categories: Omni, FOSS, Programming

I was going back over LYAH recently, and I came across the bit about Quicksort and how it's something of a poster child for Haskell because most other languages need 10+ lines of code to write it, whereas in Haskell you can do it in just a couple.

It didn't look like something that should need all that much code in Perl either, but a quick Google showed only some fairly enormous examples.

So I had a quick try, basically just re-writing the Haskell example into Perl. Which has no list comprehensions. But it does have map and grep, which accomplish much the same thing.

Here it is:

sub quicksort {
    my $array = shift;
    return [] unless (@$array);
    my $head = shift @$array;
    return [    @{ quicksort([grep { $_ <= $head } @$array])},
                $head,
                @{ quicksort([grep { $_ > $head } @$array])}
                ];  
    }   

And an example usage:

my $result = quicksort [10,2,5,3,1,6,7,4,2,3,4,8,9];
$, = ',';print @$result,"\n";

$ ./qs.pl 
1,2,2,3,3,4,4,5,6,7,8,9,10,

So, four lines of perl. You could get it down to three if you just used $_[0] instead of assigning it to $array, but I suppose some might say that the greps should be counted as a line of code each. Still only half a dozen lines tho.

I don't see what all the fuss is about :)

 

Mon, May 13, 2013

[Icon][Icon]Git prompt: Tell me more

• Post categories: Omni, FOSS, My Life, Programming, Helpful

tl;dr - The Bash __git_ps1 git prompt does more if you set a few environment variables

If you're a command-line devotee, you'll be aware of tab-completion.

And if you're a git user, I really hope you're aware that it comes with its own tab completion files, which allows it to auto-complete not just commands, but branch names and other such helpful things.

If you're not, you'll find it in git's contrib/completion/ directory. If you're a bash user, copy the git-completion.bash script to /etc/bash_completion.d/git

The nice thing about this script is that it also comes with a helpful functionality that you can insert into your PS1 - the environment variable that defines what your command prompt should look like.

To add this, add the string \$(__git_ps1 \"(%s)\") to your $PS1:

djh@devel $ echo $PS1
\u@\h $
djh@devel $ export PS1="\u@\h \$(__git_ps1 \"(%s)\")$ "
djh@devel (develop)$ echo $PS1
\u@\h $(__git_ps1 "(%s)")$
djh@devel (develop)$ 

And yay, I now have the current branch on display in my command prompt!

There's more to it than that - the prompt also tells you when you're in the middle of a rebase, or a merge; it shows you when you're in a detached head state.. all kinds of things.

All this is pretty well known, and most git-and-bash users know about and use this stuff. (Zsh users typically seem to have their own bewildering variety of all-singing, all-dancing, multi-coloured git PS1 functionality)

But what I didn't know until this weekend, when I trawled through the source code (don't ask) is that the humble Bash git prompt actually offers a little more functionality than you might think - functionality which wasn't mentioned in any of the guides I used to set up the PS1 prompt.

Because there's a few environment variables that you can define which will add to the amount of info displayed by the prompt:

  • GIT_PS1_SHOWDIRTYSTATE
  • GIT_PS1_SHOWSTASHSTATE
  • GIT_PS1_SHOWUNTRACKEDFILES

If you set these vars to a non-empty value, you'll get (respectively):

  • a * when there are unstaged changes, and a + when there are staged changes
  • a $ when there are stashed changes
  • a % when there are untracked files present

Thusly:

djh@devel (develop)$ export GIT_PS1_SHOWDIRTYSTATE=1
djh@devel (develop *+)$ export GIT_PS1_SHOWSTASHSTATE=1
djh@devel (develop *+$)$ export GIT_PS1_SHOWUNTRACKEDFILES=1
djh@devel (develop *+$%)$ 

(Yes, I had a rather dirty checkout at the time of writing :)

I'm giving serious thought to writing my own Git prompt in C, that'll show me other such useful things as the number of staged/unstaged/untracked files - more as a learning exercise than out of any belief that someone else hasn't already done so.

But in the meantime, this is a surprisingly helpful addition to what I always thought of as a brilliant, but somewhat bare-bones, bash function.

 

Mon, May 06, 2013

[Icon][Icon]3D printers - worry for the right reasons

• Post categories: Omni, FOSS, In The News, Technology, Science:ItWorks

So 3D printing is headlining again with the news that they've worked out how to print a working gun.

This is sparking off a bunch of "Gun control is now impossible, the whole world will become like the US", "3D printers must be regulated now!" comments from people. And they're also attracting the usual "Meh, 3D printers will never be common enough to worry" naysayers.

First off, let's address the misconception that the big problem with gun control is the availability of guns. It isn't. It never has been. Even if you ignore the enormous numbers of guns available from antique shops that can be easily put back into service, you can find DIY guns on Amazon, and you can download plans off P2P networks for building a handgun using nothing but standard hand tools and plumbing parts. You can download the files necessary for any CAD machine to make you pretty much any gun, too.

For reasons I've never understood, when methods to reduce gun crime are discussed, the conversation is ALWAYS about the guns. But a gun is just a paperweight if it doesn't have ammo. Bullets are harder to make and you need a constant supply of them if you want your gun to be a weapon.

3D printing a gun is just a matter of knowing what shapes to print. 3D printing of bullets is a whole different question. You need the right chemicals in the right proportions and strict safety measures to make sure they don't go off whilst you're in the middle of making them.

No, a machine that can just print out a steady stream of bullets for any idiot with a grudge is still a long way off. And hell, by the time it's here, they're probably have gotten far enough with research into carbon fibre, spider silk, and all the other interesting stuff that's going on out there that a luxurious silk shirt with be so strong it'll stop a bullet anyway.

And that's where we come into explaining why the naysayers are wrong about 3D printing being a lot of hype over a useless product.

They're the kind of people who, not that many years ago, would have said "Computers can talk to each other over the phone lines? So what, hardly anyone has a computer. If I want someone to read something I wrote, I'll mail it to them. What a useless, one-trick piece of technology."

And here we are now with a world-wide network giving rise to immense collaborative projects like Wikipedia and Linux. Social networks. New programming languages.

3D printers today are where a few primitve yet highly-expensive computers were a few decades ago - just laying the foundations of awesome, world-changing things.

Seriously, look at what we can do today with the class of machine known as 3D printers:

  • Print plastics in any shape.
  • Print most metals in any shape
  • Print some simple electronic devices
  • Print with microscopic resolution
  • Print scaffolds for biological structures
  • Print with stem cells
  • Print bona fide working new organs
  • Print DNA that can be inserted into existing cells

We already have 3D printers that allow for cells to be taken from your body, genetically modified, and used to print you new organs.

We already have 3D printers that can work on nanotechnology scales, making machines with parts so tiny you can't see them with the naked eye.

We already have 3D printers that can be used to make devices that store and use electricity.

Sure, they're big and expensive and mostly limited to huge corporations and research universities. But so were the computers that made up the Internet just a few years ago.

Everything that could be done by a vastly-expensive computer that filled up a whole room back then, and a lot more besides, can be done by a smartphone that fits in your pocket today.

So when you look at the sheer amount that can be done with 3D printers today, and factor in the same kind of advancement that happened with computing.. if you still can't see that 3D printing will literally revolutionise life on this planet, you're displaying an awesome lack of vision.

Imagine hospitals that don't have to wait for donors for organ transplants, they just make you new ones on demand. Then imagine being able to decide you want new eyes with the same colour perception as a mantis shrimp.

Imagine being able to print at at home any electronic device you can think of. Then imagine being able to download files from the Internet that will allow you to print out a device that has been created by the collaboration of thousands of people all over the world.

Imagine being able to grow bacteria that can be customised to manufacture any medicine you might need or want. Whether aspirin or heroin, if one organism can make them then others can be altered to do so.

And that's where you get into the aspect of 3D printing that *should* make you, if not scared, then at least a little dizzy.

They won't make it hard to regulate guns.

They'll make it hard to regulate *anything*

And it's unstopabble - because we're already most of the way to being able to use 3D printers to make more 3D printers.

If you can't stop people geting hold of 3D printers - and you can't if supplies are unlimited - and you can't stop them downloading ways to use them - and if you can't since it's just another type of file sharing - and you have 3D printers that can make devices, organs, pharmaceuticals, and whole new types of life...

Then you've got a world where patents are irrelevant, regulation is impossible, and neither Big Business nor Governmnet has control nor any way of regaining it.

The Internet has so far been mostly limited to letting people collaborate on building software. And as a result, we've seen the creation of titans like Android and iOS (Both Unix based), and amazing tools like whole new programming languages (Perl, Python, PHP, Ruby... the list is endless) and collaboration software like Git and BitTorrent.

Take that information-sharing, collaborative spirit. Mix into it the creativity of Instructables and Lifehacker and Make magazine. And then enable it all with 3D printers capable of making literally more things than you can imagine.

That's the future we're building towards, folks.

So don't get too hung up on the idea that a few people will be able to make a few plastic guns along the way.

 

Tue, Apr 30, 2013

[Icon][Icon]Please, stay away from rebase

• Post categories: Omni, FOSS, Rant, In The News, Technology, Programming, Helpful

I came across this plea on Hacker News to always use "git pull --rebase" instead of the default merge behaviour.

The logic was that if somebody has pushed to the remote branch since you last did a pull, and you've also made local commits to it, you'll get a merge commit. And if this happens frequently, you get a history that's mostly merges, and this is ugly and clutters your history.

I agree that having lots of merge commits is a Bad Thing. But I also contend, and will in this post try to persuade you, that not only is rebase the wrong solution to his problem, it is so often the wrong solution that (a) rebasing prevents people from learning how to use git correctly, and (b) rebasing should be regarded as a code smell - if you use it often, it's probably a symptom that you're doing something wrong.

Those are pretty sweeping claims considering that some people think that the existence of rebase is grounds for the removal of git's merging capabilities. So I've got to be pretty convincing with my arguments, I guess.

So, firstly, let's just remind ourselves: What is rebasing?

Well, if your current HEAD is commit 'a', and you make some changes and commit them, you have based your changes off commit 'a' to get commit 'b'. If somebody, in the meantime, made their own commit, commit 'c', also based off commit 'a', then you have a problem: you both want the head of the current branch to contain your changes, but you appear to have forked the branch.

The standard way of fixing this is to create a new commit that has both 'b' and 'c' as parents, merging them so the new HEAD has both your changes:

  d
 / \
b   c
 \ /
  a

The alternative is to rebase: To apply the changes you made in commit 'b' to the changes THEY made in commit 'c'. This results in a completely new commit, commit 'b1', and a smaller & simpler commit history:

 b1
 |
 c
 |
 a

So that seems superior, right? Clean, linear, compact history; every commit is a meaningfull change. Much nicer than the fork-away, merge-back alternative with its commits that do nothing other than bring branches back together again.

Well, it might *look* nicer, but it comes with problems, too. The biggest one is that timestamps are always preserved. So if you created commit 'b' before they committed 'c', but you didn't push it until later, rebasing will give you a linear history that's no longer in chronological order.

In our simple one-off examples above, this is no big deal. If you've got an entire history that's been heavily-rebased and your problem is "This bug started happening on Tuesday last week", you have a big problem: You can't just track back through your simple, linear branch until you get to last Tuesday's commits. You have to keep going back until you're absolutely certain there are no other commits further back in the history that are newer chronologically.

If you aren't aware of this and you start running your "git bisect" using your "good" base as the last commit made on Monday last week, you'll go through a long and time-consuming process that will be a total waste of time because the real culprit was actually in a commit made on Tuesday that happened (according to git) before Monday!

The "simple linear history" is a lie. The branched history might not be as pretty, but it's an accurate representation of what happened. If you see two branches in your log, you know you need to track both of them for the offending commit.

The whole reason to use a VCS is to have it record your history. Rebasing destroys your history, and therefore destroys the point of using a VCS.

"But without rebasing you get so many merge commits," I hear you cry.

I disagree. You only get the plethora of merges if you're using git wrong.

If you've never seen Linus Torvalds' talk on git, I recommend watching it. Because at one point, you'll hear him explain why he thinks Subversion is stupid - because they made it really easy to branch, but it's really hard to merge your branches back afterwards. (Having been through the process using svn, btw, I completely agree with him - it sucks)

Git was designed from the ground up to make it easy to branch, and easy to merge. People who have the misfortune of coming to git from other VCS's tend to carry in a philosophy of "Branches are hard" and thus they try to avoid it. They'll do all their work on master, because that's what they're used to.

But this is git. Branches are easy. You should use them. You should use them more than you do. And I'm confident in saying that, because I've never yet met anyone (myself included) who branches as often as they should.

It's so tempting to stay on master, to think "It's just a quick fix, it's not worth branching for!"

Or to think "I created a new branch for my project, we will now all work on the project branch" when you should instead say "I created a new branch for my project, we will now all work on feature branches forked off from the project branch."

This is where rebasing starts to hurt your git usage: Because you can rebase to avoid a merge-filled history, you will do so. And so you won't learn that what you should have done instead is to be on a branch. Here's a golden rule for using git that far too few people follow: You should never be working on a branch that other people will be pushing commits to. Fork it.

That will seem like overkill to some people: A branch off master for the project, and then a branch off the project for each feature?? You might wind up with a dozen branches!

Yes. You might. So what?? Back to my mantra: This is git. Branches are cheap. Merging is easy. You are not using enough branches.

If all your work is on a feature branch, it doesn't matter that other people are updating master: Their commits do not affect your branch. When you want to publish your work, checkout master, pull it, then merge in your branch. You get one merge commit, and you get a history in your VCS that is a true match for what actually happened. If instead you had rebased, you'd have a "Hitler Diaries" type of history - one that might seem to match real history on a casual glance, but turns out to be a pack of lies when you look closer.

So what about changes that genuinely aren't worth branching for? Correcting a typo you just noticed in a comment, for instance?

Sure. Don't branch for that - I wouldn't. But do:

  • "git pull" before you make any changes - someone else might have fixed the typo already.
  • Make the change, commit it, pull - it's unlikely that anyone else will have pushed in the meantime, but be sure.
  • Oh noes! Somebody pushed a commit in that tiny window of opportunity! Now I have an ugly merge commit! :(

You have two options here: A soft reset back to origin's HEAD, and then re-commit your work. Or go right ahead and do an interactive rebase to fix up your history. It's only a tiny change. Nobody is ever likely to care. The occasional white lie is fine ("That new haircut really suits you!") - outright, ongoing deception ("I love you and want to marry you, it's nothing to do with your money") is not.

What about fixing up history for reviewers? Say, if you make a commit that introduces a bug, but don't notice it until a few commits later. The reviewer going through commit-by-commit is likely to spot it and flag it before they see that you fixed it later. Rebasing solves that.

True enough. But - like the typo fix above - this should be a very rare occasion. If you're consistently writing buggy code and rebasing to fix it, then you're coding badly. Don't fix the symptom by rebasing endlessly, figure out your problem. And you do have a problem, because not only are you writing crap code, but you're committing it as well!

Look closer at your diffs. Write more unit tests. Run them more often. Whatever, figure out what you need to do to avoid routinely making bad commits.

Because if you keep your work on the main branch and you frequently commit bad code, then the day will come when you hit the absolute no-no of rebasing: You'll push a bad commit to a remote, and then you'll be stuck because you absolutely must not rebase published history.

Rebase is like a painkiller - it's perfectly ok to use it from time to time. But if you're using it daily, then you have an underlying problem that you need to solve. Don't keep hiding the symptom, diagnose and fix the real issue.

You get merges every time you pull? Get onto a branch!

You keep committing bugs? Test and review your code before you commit it!

You need to condense a dozen "work in progress" commits into a few "worthwhile" commits? Soft reset when you come back to a branch you had a WIP commit on, don't keep unwanted bad commits in your private branches.

You need to split a single huge commit into more atomic commits? Commit more often and look up "add -p".

You really, really need to collaborate in real-time with another dev. and so must share all your code? At this point you're pair-programing - maybe look up GNU screen & its 'acladd' command to allow you to share a terminal with your collaborator. Or just tell each other when you're about to commit.

I use git every single day of my working life. On repos I share with colleagues and we all push work to. I cannot remember the last time I used rebase - I certainly haven't used it this month, I possibly haven't used it this year.

It has valid uses. But they are few and far between. You can only ever use it on non-published history; you shouldn't use it on large numbers of commits; it's rarely needed when dealing with small numbers of commits.

The best thing that could happen to rebase is that it gets relegated to "power tool that you don't find out about until you're a git wizard" because far too many people use it as a crutch to support their ability to use git without understanding it.

If you use rebase more than once a week, I maintain that you have a problem. It might be hard to spot, it might be rough on your ego, but that's my opinion. And if you can figure out what the problem is, and fix it, then you're the one who benefits.

Rebuttals or use-cases for rebase that I haven't considered are welcome in the comments.

 

Wed, Apr 03, 2013

[Icon][Icon]Protip: Enable !$

• Post categories: Omni, FOSS, Technology, Helpful

This is something that I take so much for granted that I kind of forgot that there was a time I didn't know it. It only clicked when I watched a co-worker do something on one of my screens this morning.

So, if you've frequently in the command line, you might be used to command sequences like this:

mkdir some_dir_name/
cd some_dir_name/

Bash helpfully has a shortcut that it puts the last argument of your previous command into. It's called !$ and it allows you to replace the above sequence with

mkdir some_dir_name/
cd !$

It's almost always going to be less typing to use it than to re-type by hand. However, the command line being what it is, you don't always get to put the argument you want to 'recycle' at the end of your command.

As an example, when we have to work on COBOL (I know, I know) files, a frequent command pattern would be:

vlog FILE.CBL | less                # Find the version you want in the VCS
pget -r[version number] FILE.CBL    # Get the version you want
vi !$

The problem is the log shows most-recent at the top, and in almost every case goes well past a single screen of text, so it has to be piped to a pager. $! now has 'less' in it instead of the filename I want.

That's no good!

But hey, this is Bash. We can fix it, and further reduce the amount of typing we need to use at the same time.

I simply defined a new function in my .bashrc:

function vl {
  vlog $1 | less
  }

With this shorter command putting the "less" in for me, I can now shorten the previous example to:

vl FILE.CBL
pget -r[version number] !$
vi !$

Much better! Plus less prone to me forgetting to put the "less" at the end and having to watch dozens of pages of logs go past before I can fix my mistake.

But what about times when you need to put an intermediate command before the command that will use the !$, you may ask. e.g.

mkdir foo/
mkdir bar/
cd foo/

Yes, it's a contrived example - you could just swap the mkdir's around. But maybe you just created foo/ and then realised you needed bar/ as well. Work with me, here :P

In this situation, you can use ; to put two commands onto one line:

mkdir foo/
mkdir bar/; cd !$

The !$ gets expanded before the command gets split into two, so mkdir bar/; cd !$ becomes mkdir bar/; cd foo/

Lastly, in case of paranoia, or occasions when you want to use a slight modification of what's in !$, there are two ways to work around it.

Firstly, pressing the escape key followed by the period, [esc]-. will insert the contents of !$ into the current command, and you can then hurriedly modify it.

Secondly, there's expansion: Ctrl-Meta-E ("meta" may be either Alt or Escape depending on your setup) - this is also really handy to know about if you use a lot of aliases. It expands the current command into the command bash will run.

So if you have, say alias fbb='cd ~/foo/bar/baz' set up to make it quick & easy to get to the frequently-used ~/foo/bar/baz directory and you want to go straight to just the ~/foo/bar directory, instead of doing

fbb
cd ..

You could do

fbb
Ctrl-Meta-E

You now have the command cd ~/foo/bar/baz under your cursor, and can simply delete the 'baz' and hit return.

But we're getting into slightly more exotic territory here. The main thing I want to hilight is how useful it is to use !$ - if you're going to perform more than one operation on the same file, it's well worth knowing about; and it's also well-worth setting up functions that allow you to make use of !$ in frequently-used commands that don't usually allow it, such as the above function to remove the need to pipe to 'less'

It might seem like a tiny tweak, but once you get used to it, watching anybody who doesn't use it will make you wince. Not just at how much it slows them down, but also at how often they typo and have to correct the filename that they didn't need to re-type in the first place.

 

:: Next >>

[Links][icon] My links

[Icon][Icon]About Me

[Icon][Icon]About this blog

[Icon][Icon]My /. profile

[Icon][Icon]My Wishlist

[Icon]MyCommerce

[FSF Associate Member]


May 2013
Mon Tue Wed Thu Fri Sat Sun
 << <   > >>
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Search

User tools

XML Feeds

eXTReMe Tracker

Valid XHTML 1.0 Transitional

Valid CSS!

[Valid RSS feed]

powered by b2evolution free blog software