Copyright
Jasm
Technology 2020-2026. All rights reserved.
Here we compare Jasm code with several other
languages doing the same algorithm. This shows the simplicity
of Jasm code (smaller, cleaner, easier to understand).
The algorithm will convert water temperature
into Celsius. It will return an error if the temperature is
out of range, the units are wrong, or it fails for any other
reason.
Algorithm specification:
12 lines of code written by the
programmer, very easy to understand.
// Water temperature
may only be 0 to 100C
typedef float as
water_temperature_in_c( 0.0 to
100.0 )


proc <jerr>
ConvertWaterTemperatureToC(
temperatureInC
is ref to water_temperature_in_c,
value is float,
units is TemperatureUnits.sym_type) ; e :
// Hidden range checking for all arguments here
if (units == TemperatureUnits.CELSIUS):
temperatureInC := value
else: // FAHRENHEIT
temperatureInC := (value-32)
* 5.0 / 9.0
return ERROR_NONE
Note 1: The water_temperature_in_c type definition element
prevents an invalid water temperature with compile & run
time checking. The procedure will return ERROR_VALUE_OUT_OF_RANGE
if a value is rejected.
Note 2: The
TemperatureUnits enum in the black box
converts between numbers, symbols, & strings. It also
rejects any values not on its list with a descriptive error.
Note 3: Jasm error codes come
with descriptive text and the line number where the error
occurred.
Note 4: Comments are blue; The double blue box
is a comment.
Note 5: The red line is
a reference that returns a value.
Note 6: Error checking is never
skipped because Jasm does it automatically (preventing bugs).
No other language does this. The error checking is not shown
here because you don’t have to code it.
79
lines of user code. 5 lines are boilerplate. 42 lines are for
low-level processing; they make the code harder to understand.
Overall, this code is not easy to understand.
// Strip whitespace & carriage returns from a
string
// It panics on bad input
static void StripWhitespace(
char
*buffer, //
Pass in a buffer for the output
size_t
bufsize, //
Size of the output buffer
const
char *inputString ) // The input string
{
assert(
buffer != NULL );
assert(
inputString != NULL );
assert(
bufsize > (sizeof(inputString)+1) );
unsigned
int bufferIx = 0;
unsigned
int inputIx = 0;
buffer[0]
= 0;
// initialize output to empty string
//
Find real beginning of input
while
( isspace(inputString[inputIx])
&& (!iscntrl(inputString[inputIx]))
&& (inputString[inputIx]) )
{
if ( (iscntrl(inputString[inputIx]))
|| (!inputString[inputIx]) )
return; //
Found CR, control char, end of input
inputIx++;
}
//
Copy input to output until end is found
while
( (!iscntrl(inputString[inputIx])
&& (inputString[inputIx])) )
{
buffer[bufferIx] = inputString[inputIx];
buffer[bufferIx+1] = 0;
// Terminate the string
inputIx++;
bufferIx++;
}
//
Backtrack in output buffer and kill trailing whitespace
while
( (isspace(buffer[strlen(buffer)-1]))
buffer[strlen(buffer)-1] = 0; //
Shorten the string
}
// Enumerate the errors we can return
typedef enum {
ERROR_NONE, //
ERROR_NONE must be 0
ERROR_VALUE_OUT_OF_RANGE,
ERROR_UNKNOWN_UNITS,
ERROR_LAST
// This is how many there are
} error_code;
static const char *GetErrorCodeText(const error_code
code)
{
static
const char * const errorCodeText[ERROR_LAST] = {
“No
error”,
“Value
out of range”
“Unknown
units”
};
if
(code < ERROR_LAST)
return
errorCodeText[code];
return
“Unknown error code”;
}
// Enumerate the temperature units
typedef enum { CELSIUS, FAHRENHEIT }
temperature_unit;
const char * const temperatureUnitNameText[2] = {
“C”, “F” };
const char * const temperatureUnitNumberText[2] = {
“0”, “1” };
// Convert water temperature to Celsius using numeric
units
// unitsCode==0 means the value is in Celsius
// unitsCode==1 means the value is in Fahrenheit
error_code ConvertWaterTemperatureToC(
double
& temperatureInC,
// Return the answer here
const
double value,
// Temp
in unknown units
const
temperature_unit unitsCode )
// 0=C, 1=F
{
//
Units must be within range
if
(unitsCode == CELSIUS)
temperatureInC
= value;
else if
(unitsCode == FAHRENHEIT)
temperatureInC
= (value-32) * 5.0 / 9.0;
else
return
ERROR_UNKNOWN_UNITS;
// The value must be within range
if ( (temperatureInC<0.0) || (temperatureInC>100.0) )
return
ERROR_VALUE_OUT_OF_RANGE;
//
Successful conversation to a water temperature in Celsius
return
ERROR_NONE;
}
// Convert water temperature to Celsius using string
units
// Assume code not shown here has stripped of all
leading
// and trailing whitespace (but that code must still
be written)
error_code ConvertWaterTemperatureToC(
double
& temperatureInC,
// Return the answer here
const
double value,
// Temp in unknown units
const
char * const unitsText )
// Text for the units
{
//
Check to see if unitsText is anything we recognize
const
int celsius = strcmp( unitsText, “C” );
const
int zero = strcmp( unitsText, “0” );
const
int fahrenheit = strcmp( unitsText, “F” );
const
int one = strcmp( unitsText, “1” );
// Call
the numeric routine matching the units we found
if (
(celsius==0) || (zero==0) )
return
ConvertWaterTemperatureToC( temperatureInC, value, 0 );
if (
(fahrenheit==0) || (one==0) )
return
ConvertWaterTemperatureToC( temperatureInC, value, 1 );
// The
units didn’t match if we got here
return
ERROR_UNKNOWN_UNITS;
}
Note 1: Returning line number
& file information is possible in C, but would add more
complexity. We did not do it here.
Note 2: Code written in C++
needs a lot of hand-written low-level routines. Examples below
include GetErrorCodeText and StripWhitespace. The latter is needed to strip
all carriage returns and whitespace from the input.
Note 3: This code has some error
checking. Many programmers skimp on these checks because they
have to do it manually. Skimping on error checking is a common
source of bugs. Jasm does this error checking automatically.
Note 4: C++ is usually hard to
read. It takes some effort to make it more readable.
53
lines of code, 37 of which are for a necessary test program.
The code is moderately easy to understand, but the test
program is not.
def ConvertWaterTemperatureToC( value, units ):
“””Convert
a temperature to degrees C.
value
must be 0-100C or 32-212F
units
must be “C”, “F”, “0”, “1”, 0, or 1.
Returns
a tuple: (error code, error string,
temperature
in C).”””
#
Put arguments into a known format
value
= float(value)
# force value to number
units
= str(units)
# force units to be string
units
= units.upper()
# convert to uppercase
units
= units.strip()
# remove whitespace
if
units == ‘0’:
units = ‘C’
# change ‘0’ to ‘C’
if
units == ‘1’:
units = ‘F’
# change ‘1’ to ‘F’
#
value is now a floating-point number (or we crashed)
#
units is now a string: ‘C’, ‘F’, or other
temperatureInC
= value #
Start by assuming Celsius
if
units == ‘F’:
# Convert Fahrenheit to Celsius
temperatureInC = (temperatureInC-32) * 5.0 / 9.0
elif not units == ‘C’:
# Error: unknown units are not C or F
return (2, ‘Unknown units’, 0.0)
# The temperature is now in Celsius
# Range check it
if (temperatureInC < 0) or (temperatureInC >
100):
# Error: Temperature is out of range
return (1, ‘Temperature out of range’, temperatureInC)
# The temperature is good. Return it.
return (0, “No error”, temperatureInC)
def UnitTest():
“””Test
ConvertWaterTemperatureToC.
Return
True if good, False if bug found.”””
#
Tables of test values
celsiusTuple
= ( -1, 0, 50, 100, 101 )
fahrenheitTuple
= ( 31,
32, 122, 212, 213 )
valueGood
= (
False, True, True, True, False )
#
Tables of test units
unitTuple
= ( “C”, 0, “F”, 1, “X”, 2 )
unitGood
= ( True, True,
True, True, False, False )
#
First test Celsius
for
valueIndex in xrange(5):
for unitIndex in xrange(6):
value = celsiusTuple[valueIndex]
unit = unitTuple[unitIndex]
expectedGood = valueGood[valueIndex] &
unitGood[unitIndex]
resultCode, resultMsg, resultVal =
ConvertWaterTemperatureToC( value, unit )
resultGood = (resultCode == 0)
if not resultGood == expectedGood:
# Error: result code was wrong
return False
if resultGood:
if not celsiusTuple[valueIndex]
== resultVal:
# Error: wrong temperature
return False
#
Now test Fahrenheit
for
valueIndex in xrange(5):
for unitIndex in xrange(6):
value = fahrenheitTuple[valueIndex]
unit = unitTuple[unitIndex]
expectedGood = valueGood[valueIndex] &
unitGood[unitIndex]
resultCode, resultMsg, resultVal =
ConvertWaterTemperatureToC( value, unit )
resultGood = (resultCode == 0)
if not resultGood == expectedGood:
# Error: result code was wrong
return False
if resultGood:
if not celsiusTuple[valueIndex]
== resultVal:
# Error: wrong temperature
return False
#
No errors found
return
True
Note
1: Python is notorious for being buggy and having latent syntax
errors. The usual solution is to write more test code than the
code to be tested. The first routine here is the temperature
conversion routine and the second is its test program.
Note
2: The test code more than doubles the code to write and bugs to
be found. If the programmer skimps on test code, python code
will be full of bugs, some of them crash bugs that may not
manifest until much later. Jasm’s automatic error checking
greatly reduces the need for test code.
Note
3: Python does not have constants, enumerations, and so forth.
Making systemic changes can be a problem in their absence. Also,
there are no symbols like CELSIUS
or FAHRENHEIT available for
units. Adding, deleting, or changing a unit would be error-prone
in code like this; it would be difficult to get them all.