Problem writing data to a file after printing it

The following script, taken from a complicated encoding/decoding application for a course I’m preparing, illustrates a problem with a data vector in which printing it and then writing it to a file creates an empty file, but omitting the printing writes the file correctly, acting as if an internal data pointer is left at the end of the data by the println statement. I want the shortest possible solution and the reason why it works, since this is a course for beginning students. Thanks in advance for any help.

# codertest.jl: Exhibit Julia problem writing data after it's been printed 
# Usage: include("desktop/codertest.jl") from directory above desktop
# If the user responds y to the question, the modified string is displayed correctly
# but the output file is empty.  Otherwise, the output file has the modified data.
  bytes = Vector{UInt8}("Four score and seven years ago our fathers brought forth on this continent a new
 nation, conceived in liberty, and dedicated to the proposition that all men are
 created equal.")
  println("length(bytes)= $(length(bytes))")
  bytes[6] = 'Z' # dummy for encoding operation in real application
  println("Display modified bytes? ('y' or cr): ")
  reply = readline()
  if reply == "y" println("$(String(bytes))\n") end
  println("length(bytes)= $(length(bytes))")
  outfilename = "desktop/ctout.txt"
  outfile = open(outfilename, "w")
  write(outfile, bytes)
  close(outfile)
  println("wrote $(length(bytes)) bytes to $outfilename")
# End of codertest

String(bytes) truncates the argument to 0 length. See ?String.

It is an unfortunate interface design that will probably be fixed in 2.0. See

may I ask what is the teaching objective here? to be careful about Julia pitfalls? I think if you have a Vector of UInt you’re probably dealing with IOStream (or like) objects so stream-mutating behavior is common (not this particular one, that is)

I don’t think that running into this issue here was intended. There should be no other pitfalls in code like this, it is pretty standard IO, except that

open(outfilename, "w") do io
    write(io, bytes)
end

or even

write(outfilename, bytes)

would be more concise and take care of accidental errors during IO.

Here the issue is a surprise deviation from an otherwise commonly used naming convention,

https://docs.julialang.org/en/v1/manual/style-guide/#Append-!-to-names-of-functions-that-modify-their-arguments-1

There are no streams involved in String(bytes). A reasonably experienced, intermediate Julia user who is not aware of String doing this can easily run into this issue. This is a wart that will hopefully be fixed somehow.

1 Like

Thank you for your replies. My teaching objective is to convert
to Julia a course that I’ve successfully taught in other
languages. The full encode/decode app can be very useful in
protecting files with sensitive information. I don’t search for
Julia problems, but try to find simple solutions when they occur.
I’ll continue to do that for a while.

1 Like

Now that I’ve been told the source of the problem (thanks), a simple fix is to replace the line

  if reply == "y" println("$(String(bytes))\n") end
with
  if reply == "y" println("$(String(copy(bytes)))\n") end

with a footnote explaining to the beginning student why we write a copy rather than the original.

2 Likes