Implicit conversion to strings

Veracity

Developer
Staff member
This program:

Code:
typedef int organ;

organ LIVER = 1;
organ STOMACH = 2;
organ SPLEEN = 3;

string to_string( organ o )
{
    switch ( o ) {
    case LIVER:
	return "liver";
    case STOMACH:
	return "stomach";
    case SPLEEN:
	return "spleen";
    }
    return "none";
}

print( "organ 'LIVER' with implicit string conversion = " + LIVER );
print( "organ 'LIVER' with explicit string conversion = " + LIVER.to_string() );

string str = SPLEEN;

print( "organ 'SPLEEN' coerced via assignment to a string = " + str );
yields this:

Code:
[color=green]> concat.ash[/color]

organ 'LIVER' with implicit string conversion = 1
organ 'LIVER' with explicit string conversion = liver
organ 'SPLEEN' coerced via assignment to a string = 3
I'm using typedef as a poor-man's Enum. Or class. Or something.

I did make function lookup favor a function with a typedef argument over one with the base type, which is why my to_string was called in preference to to_string( int) - which is not actually what it does for coercion; it is done by Operation coercion, not function call.

Obviously, however, value coercion to a string does not use to_string(). Perhaps it should, if given a typedef.
 

Veracity

Developer
Staff member
I have coded this up. The following from BeachComber.ash:

Code:
typedef string [int] beach_layout;

// Function to convert a string compaticle with the _beachLayout
// property to a beach_layout map

beach_layout to_beach_layout( string squares )
{
    beach_layout layout;
    foreach i, row_data in squares.split_string( "," ) {
	int colon = row_data.index_of( ":" );
	if ( colon != -1 ) {
	    int row = row_data.substring( 0, colon ).to_int();
	    string squares = row_data.substring( colon + 1 );
	    layout[ row ] = squares;
	}
    }
    return layout;
}

// Function to convert beach layout map into a string compatible with
// the _beachLaout property

string to_string( beach_layout layout )
{
    buffer value;
    foreach row, squares in layout {
	if ( value.length() > 0 ) {
	    value.append( "," );
	}
	value.append( row );
	value.append( ":" );
	value.append( squares );
    }
    return value.to_string();
}
I have a typedef for a map and two conversion functions: string to typedef and typedef to string.

Here is a test script:

Code:
import <BeachComber.ash>;

string test = "2:rrrrrrrrrr,3:rrrrrrrrrc,4:rrrrrrrrrr,5:rrrrrrrrrr,6:rrrrrrrrrr,7:rrrrrrrrrr,8:rrrrrrrrrr,9:crrrrrrrrr,10:rrrrrrrcrr";

beach_layout layout1 = test.to_beach_layout();
print( layout1.to_string() );

beach_layout layout2 = test;
print( layout2 );
which yields this:

Code:
[color=green]> bl.ash

2:rrrrrrrrrr,3:rrrrrrrrrc,4:rrrrrrrrrr,5:rrrrrrrrrr,6:rrrrrrrrrr,7:rrrrrrrrrr,8:rrrrrrrrrr,9:crrrrrrrrr,10:rrrrrrrcrr
2:rrrrrrrrrr,3:rrrrrrrrrc,4:rrrrrrrrrr,5:rrrrrrrrrr,6:rrrrrrrrrr,7:rrrrrrrrrr,8:rrrrrrrrrr,9:crrrrrrrrr,10:rrrrrrrcrr
The first explicitly uses the conversion functions to go from a string to a beach_layout and then to a string.
The second does those implicitly when you assign a string to a beach_layout and then print the beach_layout.

Here's another test:

Code:
typedef int organ;

organ NONE = 0;
organ LIVER = 1;
organ STOMACH = 2;
organ SPLEEN = 3;

string to_string( organ o )
{
    switch ( o ) {
    case LIVER:
	return "liver";
    case STOMACH:
	return "stomach";
    case SPLEEN:
	return "spleen";
    }
    return "none";
}

print( LIVER );

print( "organ 'LIVER' with implicit string conversion = " + LIVER );
print( "organ 'LIVER' with explicit string conversion = " + LIVER.to_string() );

string str = SPLEEN;
print( "organ 'SPLEEN' coerced via assignment to a string = " + str );

organ to_organ( int i )
{
    switch ( i ) {
    case LIVER:
	return LIVER;
    case STOMACH:
	return STOMACH;
    case SPLEEN:
	return SPLEEN;
    }
    return NONE;
}

print( "to_organ( 1 ) = " + to_organ( 1 ) );
print( "to_organ( 2 ) = " + to_organ( 2 ) );
print( "to_organ( 3 ) = " + to_organ( 3 ) );
print( "to_organ( LIVER ) = " + to_organ( LIVER ) );
print( "to_organ( STOMACH ) = " + to_organ( STOMACH ) );
print( "to_organ( SPLEEN ) = " + to_organ( SPLEEN ) );

organ o = 3;
print( "int 3 coerced via assignment to an organ = " + o);

int o_to_i( organ o )
{
    switch ( o ) {
    case LIVER:
	return 1;
    case STOMACH:
	return 2;
    case SPLEEN:
	return 3;
    }
    return 0;
}

print( o_to_i( 2 ) );
which yields:

Code:
[color=green]> concat[/color]

liver
organ 'LIVER' with implicit string conversion = liver
organ 'LIVER' with explicit string conversion = liver
organ 'SPLEEN' coerced via assignment to a string = spleen
to_organ( 1 ) = liver
to_organ( 2 ) = stomach
to_organ( 3 ) = spleen
to_organ( LIVER ) = liver
to_organ( STOMACH ) = stomach
to_organ( SPLEEN ) = spleen
int 3 coerced via assignment to an organ = spleen
2
With prints in the coercion functions, you can see int coerced to organ coerced to string, and such.
Looking at the parse tree (via "debug ash on; validate concat.ash; debug ash off) I wam amused to see that:

print( to_organ( SPLEEN) )

coerces SPLEEN (an organ) to an int, which is passes to to_organ( int ), and then it passes the result to to_string( organ ).

Which is to be expected.

I'll write some more tests, since this "look up coercion functions for typedefs (and records)" happens in a lot of places. We see it in variable initialization, assignment, function calls, expressions, and return values in these tests. I need to test map and array literals and record initialization.
 
Top