D - printf and read/write a proposal
- Patrick Down (74/74) Nov 07 2003 In the spirt of the current printf and streamed I/O
- Charles Hixson (38/149) Nov 07 2003 I would rather propose that some methods be added to object. I
In the spirt of the current printf and streamed I/O
debate I'd like to offer this idea.
I know that there is resistance to adding keywords to
the language however reading and writing are such a common
operations that perhaps they is worthy of their own special
language support.
I would propose the addition of two keywords to the language
'read' and 'write'.
Syntax:
readstatement -> 'read' dataSourceObj ',' ioElement [ ',' ioElement ]+ ';'
writestatement -> 'write' dataSinkObj ',' ioElement [ ',' ioElement ]+ ';'
ioElement -> constant | variable | '.' functionName '(' paramList ')'
Some examples using these new keywords:
// Example 1
write stdOut, "Hello there";
char[] strFoo = "foo";
char[] strBar = "foo";
int foo = 12;
float bar = 1.2;
// Example 2
write stdOut,"The value of ",str," is ",strFoo,".";
// Example 3
write stdOut("The value of {0} is {1}"), strFoo, foo;
// Example 4
write stdOut("The value of {0} is {1}"), strBar, .format(bar,4,2);
// Example 5
read stdIn, strFoo;
The compiler translates the 'read' or 'write' statement into a sequence of
member function calls the data source or sink object specified in the statement.
In example 1 the compiler would translate the statement into:
stdOut.opWrite("Hello there");
stdOut.opWriteEnd();
Example 2 would be:
stdOut.opWrite("The value of ");
stdOut.opWrite(str);
stdOut.opWrite(" is ");
stdOut.opWrite(strFoo);
stdOut.opWrite(".");
stdOut.opWriteEnd();
The compiler tries to match up the types of the constants and variables in the
list that follows to opWrite or opRead member functions of the object;
An incomplete implementation of the console class for the examples above
might be:
class StdOut
{
void opWrite(char[] value) { }
void opWrite(int value) { }
void opWrite(float value) { }
void opWriteEnd();
void format(float value, int digits, int postfix) { }
FormatedOutput opCall(char[] fmtStr) { return new FormatedOutput(this,fmtStr); }
}
class FormatedOutput
{
this(StdOut strOut, char[] fmtStr) { }
void opWrite(char[] value) { }
void opWrite(int value) { }
void opWrite(float value) { }
void opWriteEnd();
void format(float value, int digits, int postfix) { }
}
The opCall and FormatedOutput class allow what happens in examples 3 and 4.
Example 4 would be translated like this:
FormatedOutput temp = stdOut("The value of {0} is {1}");
temp.opWrite(strBar);
temp.format(bar,4,2);
temp.opWriteEnd();
The read objects are similar to the write objects except that they
implement opRead;
class StdIn
{
void opRead(out char[] value) {}
void opReadEnd() { }
}
Nov 07 2003
Patrick Down wrote:
In the spirt of the current printf and streamed I/O
debate I'd like to offer this idea.
I know that there is resistance to adding keywords to
the language however reading and writing are such a common
operations that perhaps they is worthy of their own special
language support.
I would propose the addition of two keywords to the language
'read' and 'write'.
Syntax:
readstatement -> 'read' dataSourceObj ',' ioElement [ ',' ioElement ]+ ';'
writestatement -> 'write' dataSinkObj ',' ioElement [ ',' ioElement ]+ ';'
ioElement -> constant | variable | '.' functionName '(' paramList ')'
Some examples using these new keywords:
// Example 1
write stdOut, "Hello there";
char[] strFoo = "foo";
char[] strBar = "foo";
int foo = 12;
float bar = 1.2;
// Example 2
write stdOut,"The value of ",str," is ",strFoo,".";
// Example 3
write stdOut("The value of {0} is {1}"), strFoo, foo;
// Example 4
write stdOut("The value of {0} is {1}"), strBar, .format(bar,4,2);
// Example 5
read stdIn, strFoo;
The compiler translates the 'read' or 'write' statement into a sequence of
member function calls the data source or sink object specified in the
statement.
In example 1 the compiler would translate the statement into:
stdOut.opWrite("Hello there");
stdOut.opWriteEnd();
Example 2 would be:
stdOut.opWrite("The value of ");
stdOut.opWrite(str);
stdOut.opWrite(" is ");
stdOut.opWrite(strFoo);
stdOut.opWrite(".");
stdOut.opWriteEnd();
The compiler tries to match up the types of the constants and variables in the
list that follows to opWrite or opRead member functions of the object;
An incomplete implementation of the console class for the examples above
might be:
class StdOut
{
void opWrite(char[] value) { }
void opWrite(int value) { }
void opWrite(float value) { }
void opWriteEnd();
void format(float value, int digits, int postfix) { }
FormatedOutput opCall(char[] fmtStr) { return new FormatedOutput(this,fmtStr);
}
}
class FormatedOutput
{
this(StdOut strOut, char[] fmtStr) { }
void opWrite(char[] value) { }
void opWrite(int value) { }
void opWrite(float value) { }
void opWriteEnd();
void format(float value, int digits, int postfix) { }
}
The opCall and FormatedOutput class allow what happens in examples 3 and 4.
Example 4 would be translated like this:
FormatedOutput temp = stdOut("The value of {0} is {1}");
temp.opWrite(strBar);
temp.format(bar,4,2);
temp.opWriteEnd();
The read objects are similar to the write objects except that they
implement opRead;
class StdIn
{
void opRead(out char[] value) {}
void opReadEnd() { }
}
I would rather propose that some methods be added to object. I
would propose that the initial list be:
obj = Object.read (ioChannel | file)
obj.write (ioChannel | file[, formatId])
obj.toXML()
obj = Object.fromXML(xmlstring)
Note: I'm not pretending that I got the syntax correct. I'm still
in the early stages of learning D. The idea is that Object stands
for a class-level method, and obj stands for some object instance.
Here there would need to be some way for the read or fromXML method
to determine the actual class of the object being read, and to
create and return a new object of that kind. I'm not sure that this
is feasible in D, but it would be very useful if it were. Each
class would need to have a default constructor that could take the
written object as input and create an instance of the class from
that input. Of course, this would need to be overridden for some
classes (and the write method would need to be overridden in
symmetry). This would allow virtual members, etc.
Note that each instance of formatId would need to be implemented
separately. This might lead some classes to have a multitude of
simple formatID methods, so perhaps some better solution is needed,
but when one is talking about formatted output of class variables,
then simple formatted solutions don't work well.
Perhaps formatting could be simplified if one defined "views" of the
class. But even this doesn't really solve the problem. Should the
variable names be included? Are you doing a columnar list, with the
variable names at the top? Do you want "optimum width" (for some
definition of optimum) or do you want to specify? Are column
separators needed? What are page breaks, and how do you deal with
them? UGH!
When Fortran was created, everything was monospaced, 66 lines / page
(or change the carriage control tape the a custom punched one), and
either 132 or 80 columns wide, depending on the paper choice. And
only certain defined kinds of variable (float, integer, fixed length
strings..the fancier types were later). Format was a good match to
the problem space. Things are a bit more difficult when one starts
dealing with user defined objects.
Nov 07 2003








Charles Hixson <charleshixsn earthlink.net>