Showing posts with label Salted. Show all posts
Showing posts with label Salted. Show all posts

Thursday 27 August 2015

CFML: how should int() behave?

One of the scintillating conversations on the CFML Slack channel today was regarding people's expectations of CFML's int() function. Ross had this expression:

int(35 - (1013 / (13+1)))

And he quite legitimately expected the result to be -37 (the float value before converting to an int is -37.357142857143). However because CFML is daft (IMO), its integer conversion follows this rule:
Calculates the closest integer that is smaller than number.
Which means the result of the expression is -38.

What it should do is simply return the integer part of the number. It's not a rounding function, it's a conversion function.

I thought there might be a precedent in other languages, but here's some code samples:

public class TestInt {

    public static int toInt(Double f){
        return f.intValue();

Returns 37 when passed -37.357142857143.

irb(main):004:0> -37.357142857143.to_i
=> -37


groovy:000> (int) -37.357142857143
===> -37

>>> int(-37.357142857143)

user=> (int -37.357142857143)

Oops! Almost forgot PHP (I actually did forget... this is being added during a re-edit)
$f = -37.357142857143;
$i = (int) $f;
echo $i;

You get the idea.

So... it's a bit late in the game to fix int() in CFML, but John Whish has raised a ticket for ColdFusion: "Deprecate `int` in favour of `floor`" (4044533). This makes good sense to me. CFML already has a ceiling() function, so it makes sense to also have floor().

Note one can use fix() in CFML to get the right result, ie: just the integer part of the number. But that's just a fix. Pity int() didn't just do the right thing in the first place.

Is there any precedent in any other language for an int() operation to actually do rounding instead?


Monday 1 December 2014

Hammers and screws (and when not to use a list in CFML)

I hope Salted (/Ross) and Ryan don't mind me pinching our IRC conversation for a blog article, but... well... too bad if they do. It's done now. This is it.

Ross was asking "whats the most efficient way to remove the first two items in a list and get back the remainder", which made my eyes narrow and decide there's probably something to get to the bottom of here. Because he mentioned "lists". And these should - in general - be avoided in CFML.

After some back and forth with Ryan, Ross settled on:

listtoarray(foo," "), arrayslice(bar,3), arraytolist(bar," ")

(pseudo code, obviously).

Now... I think lists are overused in CFML, and - indeed - they are a bit rubbish. Having a string of data and then using one character (OK, or "some characters ~") from the string as a delimiter is seldom going to work, especially with the default delimiter of comma. Because in really a lot of situations, commas are actually part of the data. And same with any other char-based delimiter (except say characters specifically intended to be delimiters like characters 28-31 (file, group record and unit separators, respectively). I really don't think lists should generally be part of a solution to anything.

With this in mind, I decided to check what was going on. This is copy-and-pasted from the IRC log (spelling and formatting addressed, otherwise it's unabridged):

16:36 <adam_cameron> Salted: first question that should be asked... why is it a list in the first place? Do you have any control over it?
16:36 <Salted> no, it's returned from a postcode lookup service
16:36 <Salted> I'm fairly certain that the address string will always have the postcode first so [p1] [pt2] [line1]
16:37 <Salted> it's not a list its a string but I'm treating it as a space delimited list for these purposes...
16:37 <adam_cameron> so it's a string? Not a list per se?
16:37 <adam_cameron> ok
16:37 <Salted> indeed
16:37 <adam_cameron> So what you actually want is everything after the second space?
16:37 <Salted> essentially yes
16:37 <adam_cameron> Not a list with the first two elements dropped off
16:37 <Salted> in this instance what you've mentioned is one and the same, if I treat it as a list
16:38 <adam_cameron> well literally, yes. However once you start treating it as a list, you're thinking about it wrong
16:39 <Salted> I don't see how thats different from thinking of strings as char arrays, for example
16:40 <Salted> "my name is ross" is both a char array of 14 elements and a list of 4 elements
16:40 <adam_cameron> because you start trying to use list functions on it
16:40 <adam_cameron> Which makes your code shit

My point here - one that Ross doesn't entirely agree with - is that just because one can use a string as a list, doesn't mean - semantically - it is a list. And one should try to keep one's code as semantically clear as possible.

What Ross has here is not a space-separated list. Later in the conversation I extracted form him what the actual data was like, and this was a sample:

X1 2YZ Apartment 1903, 10 Random Street Suburbia, OURTOWN

What we have here is... a mess. It can be assessed in a number of ways:

  • a post code part followed by an address part
  • a post code followed by a street address followed by a city
  • a post code followed by the street part of the address, the suburb part of the address, and the city part of the address
But what it isn't is a space- (or comma-, or anything-) separated list. So one should not solve this problem using lists.

One should look at the actual requirement, and solve that.