Verifying leftPad() in Whiley
The leftPad(string,int)
function simply pads a string up to a given size by inserted spaces at the beginning. For example, leftPad("hello",8)
produces " hello"
. This little function shot to fame in 2016 when a developer pulled all his modules from NPM, of which one provided the leftPad()
functionality. There were two basic issues causing surprise here: firstly, a developer can suddenly and without warning pull all his libraries (including old versions), thereby breaking anything depending on them (which, in this case, was a lot). secondly, that someone was providing a module to offer this (pretty basic) functionality.
Anyhow, that is all ancient history. A bunch of people have been writing verified implementations of leftPad()
in various languages. And, @Hillelolgram
asked if I would write one in Whiley:
So, having little spare time, I thought I’d give it a crack. Here’s my first version:
import string from std::ascii
import char from std::ascii
import std::array
function leftPad(string str, int n) -> (string result)
// Required padding cannot be negative
requires n >= |str|
// Returned array increased to size n
ensures |result| == n
// First elements are padding
ensures all { i in 0 .. (n-|str|) | result[i] == ' '}
// Everything else copied from original
ensures all { i in 0 .. |str| | result[i+(n-|str|)] == str[i] }:
// Calculate how much padding required
int padding = n - |str|
// Create new string of final length
string nstr = [' '; n]
// Copy over everthing from old string
return array::copy(str,0,nstr,padding,|str|)
This is nice and short and makes use of the standard library. But, sadly, for reasons unknown I could not get this to pass verification. Since I already had a resize()
method in the standard library and I knew this verified, I figured I could work from that instead. Here’s version two (after some faffing around):
function leftPad(string str, int size) -> (string result)
// Required padding cannot be negative
requires size >= |str|
// Returned array increased to size
ensures |result| == size
// First n elements are padding
ensures all { i in 0 .. (size-|str|) | result[i] == ' '}
// Everything else copied from original
ensures all { i in 0 .. |str| | result[i+(size-|str|)] == str[i] }:
//
int padding = size - |str|
string nstr = [' '; size]
int i = 0
//
while i < |str|
where i >= 0 && |nstr| == size
// All elements up to i copied over
where all { j in 0..i | nstr[j+padding] == str[j] }
// Untouched str are still padding
where all { j in 0..padding | nstr[j] == ' ' }:
//
nstr[i+padding] = str[i]
i = i + 1
//
return nstr
Essentially, I’ve inlined the call to array::copy()
. And, yes, this verifies!! Unfortunately, you can’t verify it on whileylabs.com at the moment because it times out. But, you can do it using WhileyWeb or the command-line compiler.
Whilst it’s great that it does indeed verify, what’s less great is the faffing around I needed to get it through…