Read an allocatable string with a namelist in Fortran - string

Since Fortran 2003 is it possible to work with variable length character strings. Instead of working in an archaic way and declaring a constant string length I would like to read the character strings of my namelist dynamically.
Consider the program
program bug
implicit none
character(:), allocatable :: string
integer :: file_unit
namelist / list / string
open(newunit=file_unit,file='namelist.txt')
read(unit=file_unit,nml=list)
write(*,*) string
close(file_unit)
end program bug_namelist
and the small namelist contained in the following namelist.txt file:
&list
string = "abcdefghijkl"
/
If I compile with GCC 8.2.0 with agressive debug flags I get
Warning: ‘.string’ may be used uninitialized in this function [-Wmaybe-uninitialized]
and at runtine, nothing is printed and this arises:
Fortran runtime warning: Namelist object 'string' truncated on read.
and with the Intel compiler 17.0.6 with similar debug flags, no compile-time flags and the following runtime error:
forrtl: severe (408): fort: (7): Attempt to use pointer STRING when it is not associated with a target
which indicates that the namelist feature is unable to allocate a variable-length string "by itself", because if I add the line
allocate(character(len=15) :: string)
the errors disappear. Is this expected behavior? Or is it a defect from the compilers?

It is expected behavior, specified by the Fortran standard. In fact, nowhere in Fortran I/O are deferred-length allocatable strings treated the way they are in intrinsic assignment. There is a proposed work item for the next Fortran standard ("F202X") to allow for this in limited contexts (see https://j3-fortran.org/doc/year/18/18-279r1.txt) If I recall correctly, we discussed adding list-directed and NAMELIST reads to this at an earlier standards meeting, but some issues were raised that I don't recall precisely and we will revisit this.

Related

perl6 "P6opaque, Str" vs simple "Str" types

I was trying to obtain a list from user input doing my usual codes, but sometimes it fails unpredictably due to this error:
This type cannot unbox to a native integer: P6opaque, Str
The code line is
my #a = prompt("Enter list: ").words || (1,2,3);
It failed only if I enter only one number.
When is a Str converted to "P6opaque, Str" without user awareness? I cannot use +#a[0] or #a[0].Int to convert this "P6opaque, Str" to an Int. What am I missing here?
TL;DR The mention of P6Opaque is a mostly a red herring. Some code is trying to assign a string to an int. You'll need to coerce it to an Int first. I know you've tried that. All that's left is to find out where it needs to be done. Hopefully this answer will guide us there.
You can only assign an integer to an integer variable
It's an error to assign a string to an Int or an int:
my Int $a = '1'; # Type check failed ... expected Int but got Str
my int $a = '1'; # This type cannot unbox to a native integer: P6opaque, Str
The error on assigning to an Int is caught by high level machinery which responds with a high level error message. For int it's low level machinery which responds with a low level message. We'll take a closer look at this difference below, but it's a red herring as far as fixing your problem is concerned.
To fix this problem you'll need to find where a string is being assigned or bound to a variable with a native integer type constraint like int and then coerce before the assignment with something like this:
my int $a = +'1' # Works
I know you've tried something like that. I don't know why it hasn't worked because you haven't yet shared the part of your code that's causing the problem.
Finding the problem
There must be some use of a native integer that's either directly in your code (i.e. you explicitly specified a native integer type, an all lowercase type like int, int32, uint etc.) or in some code your code uses.
So, search your code first.
If you still haven't found it, then please share enough of your code that we can reproduce the problem, preferably after reading StackOverflow's freshly Named/URLed page How to create a Minimal, Reproducible Example. TIA.
Red herring or LTA?
“P6opaque, Str” vs simple “Str” types
They're the same. P6opaque, Str is a reference to exactly the same type as Str.
When is a Str converted to "P6opaque, Str" without user awareness?
It isn't.
Quoting is repr and native representations:
P6opaque is the default representation used for all objects in Perl 6.
A representation is a set of rules for representing a type in a computer's memory.
Errors related to P6 objects are generally handled by the high level "front end" of the P6 language/compiler. High level error messages don't mention representations because most ordinary P6 objects have the same one (P6Opaque) and even when they don't the representation still won't be relevant.
But here we're dealing with an error handled by MoarVM.
MoarVM's error messages don't mention the representation if it's deemed irrelevant. For example:
my int64 $a = 2⁶³
displays a MoarVM exception with an error message about the bigint type whose representation is P6bigint:
Cannot unbox 64 bit wide bigint into native integer
This error message doesn't mention the representation (P6bigint).
But the MoarVM response to trying to put anything other than an integer into a native integer is a MoarVM exception which does mention the representation. For example, if you attempt to assign an Str it's:
This type cannot unbox to a native integer: P6opaque, Str
If someone doesn't know about representations, this message is bit opaque aka LTA. But while removing the representation removes the confusion it also removes information that might be important:
This type cannot unbox to a native integer: Str
I'm not convinced that that is actually better and/or worthwhile but if you feel strongly about it, feel free to file a MoarVM bug about this with an LTA tag.

meaning of `STRING_ELT` in Rcpp

I searched the source code of RCPP but could not find out the definition of STRING_ELT, could someone point to a reference where I could find all the definitions of the Macro like things in RCPP?
This is part of R's internals accessed via:
#include <R.h>
#include <Rinternals.h>
See 5.9.7 Handling character data of Writing R Extensions:
R character vectors are stored as STRSXPs, a vector type like VECSXP
where every element is of type CHARSXP. The CHARSXP elements of
STRSXPs are accessed using STRING_ELT and SET_STRING_ELT.
CHARSXPs are read-only objects and must never be modified. In
particular, the C-style string contained in a CHARSXP should be
treated as read-only and for this reason the CHAR function used to
access the character data of a CHARSXP returns (const char *) (this
also allows compilers to issue warnings about improper use). Since
CHARSXPs are immutable, the same CHARSXP can be shared by any STRSXP
needing an element representing the same string. R maintains a global
cache of CHARSXPs so that there is only ever one CHARSXP representing
a given string in memory.
You can obtain a CHARSXP by calling mkChar and providing a
nul-terminated C-style string. This function will return a
pre-existing CHARSXP if one with a matching string already exists,
otherwise it will create a new one and add it to the cache before
returning it to you. The variant mkCharLen can be used to create a
CHARSXP from part of a buffer and will ensure null-termination.
Note that R character strings are restricted to 2^31 - 1 bytes, and
hence so should the input to mkChar be (C allows longer strings on
64-bit platforms).

why does this string not contain the correct characters?

Written in Delphi XE3, my software is communicating with an instrument that occasionally sends binary data. had expected I should use AnsiString since this data will never be Unicode. I couldn't believe that the following code doesn't work as I had expected. I'm supposing that the characters I'm exposing it to are considered illegitimate...
var
s:AnsiString;
begin
s:='test' + chr(128);
// had expected that since the string was set above to end in #128,
// it should end in #128...it does not.
if ord(s[5])<>128 then
ShowMessage('String ending is not as expected!');
end;
Naturally, I could use a pointer to accomplish this but I would think I should probably be using a different kind of string. of course, I could use a byte array but a string would be more convenient.
really, I'd like to know "why" and have some good alternatives.
thanks!
The behaviour you observe stems from the fact that Chr(128) is a UTF-16 WideChar representing U+0080.
When translated to your ANSI locale this does not map to ordinal 128. I would expect U+0080 to have no equivalent in your ANSI locale and therefore map to ? to indicate a failed translation.
Indeed the compiler will even warn you that this can happen. You code when compiled with default compiler options yields these warnings:
W1058 Implicit string cast with potential data loss from 'string' to 'AnsiString'
W1062 Narrowing given wide string constant lost information
Personally I would use configure the warnings to treat both of those warnings as errors.
The fundamental issue is revealed here:
My software is communicating with an instrument that occasionally sends binary data.
The correct data type for byte oriented binary data is an array of byte. In Delphi that would be TBytes.
It is wrong to use AnsiString since that exposes you to codepage translations. You want to be able to specify ordinal values and you categorically do not want text encodings to play a part. You do not want for your program's behaviour to be determined by the prevailing ANSI locale.
Strings are for text. For binary use byte arrays.

Fortran improper output on AIX and Linux

I have a scenario where i declare a variable real*8 and read a value
0.1234123412341234
which is stored in a file.
When i try to read it on Linux to a variable and display the value, it prints
0.12341234123412
whereas when i run the same code for AIX it prints the value
0.12341234123412370
Why does both the platform print different values for the same code? Is there any possibility to overcome this without using format specifier?
P.S
AIX compiler is xlf
Linux compiler is ifort
I assume that you are using list-directed IO, write (X, *). While this type of IO is convenient, the output is not fully specified by the standard. If you want your output to be extremely similar across compilers and platforms, you should use a format. (You might still have small variations in results due to the use of finite-precision arithmetic.)
You shouldn't use REAL*8 for declaring double variables, you should use
INTEGER, PARAMETER :: prec = SELECTED_REAL_KIND(15,307)
REAL(prec) :: variable
to specify a portable double-precision variables (see here for more details).
In any event, the problem you are experiencing is related to precision. A double-precision variable can go to 15 digits before becoming wrong, which appears to be the case with both compilers. In fact, I would argue that these are indeed the same number because of how close they are (a % difference of about 3E-12).

How to convert AnsiString into an Integer in modern Delphi?

This is a little different from SameText question.
I need to convert AnsiString into an Integer.
var
param: AnsiString;
num: Integer;
begin
if TryStrToInt(param, num) then
...
In pre-Unicode Delphi I would use TryStrToInt function, but in modern Delphi there is only Unicode version of it, so I'm getting this warning: W1057 Implicit string cast from 'AnsiString' to 'string' upon call.
My question is, how to properly convert AnsiStrings in modern Delphi without getting compiler warnings (and without superfluously having to cast string to UnicodeString(text))
Various options are available to you:
Accept and embrace Unicode. Stop using AnsiString.
Use an explicit conversion to string: TryStrToInt(string(param), num).
Disable warning W1057.
Perform the conversion from ANSI to UTF-16 yourself with a call to MultiByteToWideChar. This isn't a serious option, but if you want to leave W1057 enabled, and not use an explicit conversion, then it's what is left.
Frankly, option 1 is to be preferred. If you try to persist the use of AnsiString through your code you will be wallowing in an endless morass of casts and warnings. If you have a need for ANSI encoded strings it is likely to be at an interop boundary. Perhaps you are reading or writing files that use ANSI encoding. Perform the conversion between ANSI and UTF-16 at the interop boundary. The rest of the time, for your internal code, use string.
how to properly convert AnsiStrings in modern Delphi without getting
compiler warnings (and without superfluously having to cast string to
UnicodeString
If you don't cast from AnsiString to String, the compiler will do it for you. You can't avoid the cast. It's just a matter if you explicitly do it, or the compiler does it for you implicitly.
When you explicitly do the conversion in code (via cast), then the compiler doesn't worry about the side effects. It assumes you know what you're doing and leaves you alone.
You'll have to choose one. Compiler warning or explicit casting.
You could technically turn those compiler warnings off (but don't do this):
W1057 IMPLICIT_STRING_CAST ON Implicit string cast from ‘%s’ to
‘%s’ (Delphi)
W1058 IMPLICIT_STRING_CAST_LOSS ON Implicit string cast with
potential data loss from ‘%s’ to ‘%s’ (Delphi)

Resources