octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: String display


From: Andrew Janke
Subject: Re: String display
Date: Wed, 23 Oct 2019 18:34:28 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.9.0

Here's something else to consider while we're on the subject: the disp()
API has some limitations, especially when it comes to customizing output
for compound data structures.

Disp:
a) Combines both conversion of a data value to a displayable string
representation, and the outputting of that string to the console
b) Operates on an entire array at once, instead of on individual elements
c) Does not call disp() overrides for user-defined classes which are
displayed inside a compound data structure like a struct or cell array.

For example, b) is an issue if you want to compose some arrays into a
dataframe or table with heterogeneous columns: say you have a table foo
with a double, a char or cellstr, and a datetime object. The
dataframe/table class's disp needs to have string representations for
each element of the double and datetime arrays, and special handling for
the char/cellstr column. And then it needs to arrange those in its own
2-D layout, maybe with cell borders and whatnot.

Or let's say you make a struct with a double and a datetime in its fields.

>> s = struct('foo', 42, 'bar', datetime('2019-01-02 12:34'))

I'd like it to display like this:

s =
  scalar structure containing the fields:
    foo = 42
    bar = 02-Jan-2019 12:34:00
>>

Not like this:

s =
  scalar structure containing the fields:
    foo =  42
    bar =
    <object datetime>

>>


For Matlab programming, I came up with my own generic API called
"dispstr" to handle this: https://github.com/apjanke/dispstr. It defines
conventional, overridable functions dispstr() and dispstrs() that do
just the string conversion step of disp(), and do it respectively for
either an entire array, or for each element in an array. (Because it's
an add-on and not part of Matlab itself, I had to do horrible things
with monkeypatching to get it to work nicely. They're so horrible that I
didn't even include them in the public repo.)

Octave's disp() isn't as bad as Matlab's, because you can capture the
output without evalc(). But it still has the other limitations. And in
the case where you're disp()ing a string, you can't really tell whether
the user intended to generically get the string representation for a
value, or if they just wanted a convenient way to put some text on the
console.

Maybe Octave would like to consider something like that? Many other
modern programming languages, especially high-level or OOP ones, have an
equivalent, like toString, to_s, str/repr.

I realize this would be a big change, so it's not something to take on
lightly.

Cheers,
Andrew

On 10/23/19 5:47 PM, Rik wrote:
> jwe,
> 
> It's trivial to get 90% of the way there, but the last 10% is going to be a
> PITA.  See the attached diff.
> 
> The trouble is that disp() does not print surrounding characters around
> strings, and disp() is used by all the print routines in the octave-value
> directory.  This is required because disp() might be overloaded by a
> user-defined class.  Here's a backtrace showing that display() is called to
> print the name tag, which then calls disp(), which then calls the print
> routines which are overloaded for a particular octave_value type
> 
> #0  octave_print_internal (os=..., chm=..., pr_as_read_syntax=false,
> pr_as_string=true)
>     at libinterp/corefcn/pr-output.cc:2628
> #1  0x00007f097b2a9976 in octave_print_internal (os=..., nda=...,
> pr_as_read_syntax=false,
>     extra_indent=0, pr_as_string=true) at libinterp/corefcn/pr-output.cc:2678
> #2  0x00007f097ad15ef3 in octave_char_matrix_str::print_raw
> (this=0x7f0944456fc0, os=...,
>     pr_as_read_syntax=false) at libinterp/octave-value/ov-str-mat.cc:260
> #3  0x00007f097ac6f3fc in octave_base_matrix<charNDArray>::print
> (this=0x7f0944456fc0, os=...,
>     pr_as_read_syntax=false) at libinterp/octave-value/ov-base-mat.cc:454
> #4  0x00007f097acf7000 in octave_value::print (this=0x7f0951317500, os=...,
> pr_as_read_syntax=false)
>     at ./libinterp/octave-value/ov.h:1233
> #5  0x00007f097b2ae343 in Fdisp (args=..., nargout=0) at
> libinterp/corefcn/pr-output.cc:3350
> #6  0x00007f097ac5bde5 in octave_builtin::call (this=0x7f094409a960,
> tw=..., nargout=0, args=...)
>     at libinterp/octave-value/ov-builtin.cc:62
> #7  0x00007f097b1a7616 in octave::interpreter::feval (this=0x7f0944004a60,
> name="disp", args=...,
>     nargout=0) at libinterp/corefcn/interpreter.cc:1402
> #8  0x00007f097b1a74a5 in octave::interpreter::feval (this=0x7f0944004a60,
>     name=0x7f097b3b90c5 "disp", args=..., nargout=0) at
> libinterp/corefcn/interpreter.cc:1388
> #9  0x00007f097ade7402 in octave::feval (name=0x7f097b3b90c5 "disp",
> args=..., nargout=0)
>     at libinterp/parse-tree/oct-parse.yy:4950
> #10 0x00007f097b2ae884 in Fdisplay (args=...) at
> libinterp/corefcn/pr-output.cc:3517
> #11 0x00007f097ac5bde5 in octave_builtin::call (this=0x7f094409afa0,
> tw=..., nargout=0, args=...)
>     at libinterp/octave-value/ov-builtin.cc:62
> #12 0x00007f097b1a7616 in octave::interpreter::feval (this=0x7f0944004a60,
> name="display",
>     args=..., nargout=0) at libinterp/corefcn/interpreter.cc:1402
> #13 0x00007f097b1a74a5 in octave::interpreter::feval (this=0x7f0944004a60,
>     name=0x7f097b3953d0 "display", args=..., nargout=0) at
> libinterp/corefcn/interpreter.cc:1388
> #14 0x00007f097ade7402 in octave::feval (name=0x7f097b3953d0 "display",
> args=..., nargout=0)
>     at libinterp/parse-tree/oct-parse.yy:4950
> 
> The simplest solution would be to have some knowledge of whether this
> particular call to print was being done on behalf of the interpreter or
> not.  Then the code within the overload of octave_print_internal for
> charMatrix becomes
> 
> if (for_interpreter)
>   os << '\'' << row << '\'';
> else
>   os << row;
> 
> But I don't have a good idea of how to pass that information down.
> 
> --Rik
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]