Uli wrote (replying to Scott):
> >The only other thing I thought of was to use a varargs-type parameter
> >list (i.e., pointer to an array with the number of elements passed as
> >a separate parameter) but instead of passing a null-terminated string,
> >you pass something like a pascal string except that the count would be
> >stored as a 4-byte integer instead of as single byte. Saves a few
> >mallocs (which is always good), but does require some casting (which
> >isn't).
>
> Scott,
>
> There's just one problem with this: Once we introduce UniCode or wide
> chars, we'll be royally screwed up with this. Or we'd have to add
a flag to
> each such object telling whether it's Unicode or ASCII.
>
> Since most hosts already have a built-in string object, maybe we could
> create an opaque object type instead (I have to admit, since Apple
began
> using opaque types, I'm a real sucker for these critters). Anyway,
in that
> case we'd have a pseudo-OO design that will be much more easily
extendable.
> Well, we'd define a data type that is the size of a memory address
> (pointer) as being a ParamStrRef. And then we provide callbacks
(they're
> not too costly these days, speed-wise, are they?) to create such
an object,
> to manipulate it etc.
>
> ParamStrRef CreateEmptyString();
> ParamStrRef CreateStringFromCString( char* str );
> ParamStrRef CreateStringFromText( unsigned long length, char*
txt );
>
> void CopyCStringToString( ParamStrRef str, char* inStr );
> void CopyTextToString( ParamStrRef str, char* inStr,
> unsigned long inLength );
>
> void CopyStringToCString( ParamStrRef str, char* outStr,
> unsigned long maxLength );
> void CopyStringToText( ParamStrRef str, char* outStr,
> unsigned long *ioLength );
>
> void ReleaseString( ParamStrRef str );
>
> Later when UniCode arrives we could extend these callbacks to
create and
> copy strings from/to Unicode strings, etc. And best of all, if the host
> internally uses Unicode, one would just have to make the ASCII-string
> callbacks convert from Unicode. This is so flexible that we could
even (if
> we wanted) provide access to other data types besides strings,
e.g. arrays,
> or even longs, shorts, colors etc. although we might then change
the name
> from ParamStrRef to XCMDParamRef or something like that.
>
> >So who'd be responsible for deleting these beasties?
>
> I guess it'd be best if we established a general rule. All
strings are to
> be released by the external, except those that need to exist befor
or after
> the external call (i.e. parameters and result belong to the host).
>
> BTW -- "Text" is what I call a non-terminated string with a
length long.
> Choose any other name if it suits you better, this is just a draft
to help
> where my English fails.
>
> Tsch�ss,
> -- M. Uli Kusterer
>
I think this is an excellent suggestion. It's time to move beyond
simple C structs and start embracing more robust object-oriented
approaches.
I think we should at least include numbers along with strings in our
list of supported data types. While xTalk languages are essentially
typeless, allowing the user to treat all data as strings, internally
they all store numbers as numbers until a string representation is
called for. So it makes sense to allow externals to accept and
provide numeric values directly to save some unnecessary conversions.
I would suggest we begin the api with the simple types (say, strings
and doubles) before trying to tackle the more complex or
implementation-specific ones like arrays and colors.
Let's make the reference generic, as Uli suggested, although I
prefer XParamRef rather than XCMDParamRef (I've also changed "Text"
to "CharArray" as being hopefully more descriptive). So, the api
then starts to look something like this:
XParamRef CreateEmptyParam();
XParamRef CreateParamWithCString( char* str );
XParamRef CreateParamWithCharArray( unsigned long length, char* txt );
XParamRef CreateParamWithDouble( double value );
void SetParamCStringValue( XParamRef param, char* inStr );
void SetParamCharArrayValue( XParamRef param, char* inStr,
unsigned long inLength );
void SetParamDoubleValue( XParamRef param, double value );
char* ParamCStringValue( XParamRef param );
char* ParamCharArrayValue( XParamRef param, unsigned long *ioLength );
double ParamDoubleValue( XParamRef param );
void CopyParamCStringValue( XParamRef param, char** outStrPtr,
unsigned long *lengthPtr );
void CopyParamCharArrayValue( XParamRef param, char** outStrPtr,
unsigned long * lengthPtr );
void ReleaseParam( XParamRef param );
The ParamCStringValue and ParamCharArrayValue calls would return
pointers to strings in memory which would be valid until the external
returns but should not be altered by the external. If the external
wants to keep the string until a later call or wants to alter the
string, it must either copy the string itself, or use the "Copy..."
callback instead.
Under this scheme, the external is only responsible for freeing the
memory if it received a copy of the string. In the cases where a
pointer is returned, it points to memory owned and managed by the
opaque object.
Regards,
Doug Simons
Thoughtful Software