Why does Julia think a vector is a string?

This works perfectly, as expected:

julia> push!(S,[2,3,4])
Stack{Any}(Deque [Any[[2, 3, 4]]])

julia> push!(S,[5,6,7])
Stack{Any}(Deque [Any[[2, 3, 4], [5, 6, 7]]])

julia> x = pop()
3-element Vector{Int64}:
5
6
7

julia> y = pop()
3-element Vector{Int64}:
2
3
4

julia> +(x,y)
3-element Vector{Int64}:
7
9
11

But, when my program does the same thing:

julia> jacli()
S: [2,3,4]
execute: term = [2,3,4]

S[[2,3,4]]: [4,5,6]
execute: term = [4,5,6]

S[[2,3,4] [4,5,6]]: +
execute: term = +

apply: x = [4,5,6] y = [2,3,4]
ERROR: MethodError: no method matching +(::String, ::String)

The printout “apply: x = [4,5,6] y = [2,3,4]” is one line before the expression f(x,y) where f = +, clearly showing that x and y are vectors. Why would Julia interpret them as strings?

What is this code? Where does S come from? What are you popping from here

?

Where does jacli come from?

What program?

This question is really confusing. Can you provide some context?

1 Like

The program is jacli. S = StackAny. jacli pushes literals, like vectors, onto S and executes functions, like +, by popping the appropriate number of stack terms, then applying the function to those terms. The operation f(x,y) where f = + and x and y are vectors, fails because Julia thinks x and y are strings! But the line “apply: x = [4,5,6] y = [2,3,4]” printed at runtime, clearly shows they are not strings.

The jacli prompt shows the current stack then waits for input.

Sorry for the confusion.

You have a bug in your program but without reproducing enough of it here for us to try it out, it is impossible to say what it is.

2 Likes

The bug appears to be that Julia is treating vectors x and y as strings in the
expression +(x,y).

Should I post the source code to my program, it’s rather long?

Quoting from Please read: make it easier to help you. You don’t have to post whole source codes. It’s best to give us a self-contained minimal working example so we can reproduce your error. I believe people reading your post doesn’t understand several things:

  1. the process of defining S
  2. what function is pop() (because it accepts no argument) in julia we have the method pop!()
  3. what function is jacli()

and it’s best to write your code in the triple-backticks. lastly, doing an addition of Vector{Int64} to another Vector{Int64} still results a Vector{Int64} the last time I checked.


julia> x = [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> y = [4,5,6]
3-element Vector{Int64}:
 4
 5
 6

julia> +(x,y)
3-element Vector{Int64}:
 5
 7
 9

Edit: I see you’ve edited the post @dgpdx to give an explanation, but still I haven’t yet understand what happened

1 Like

What happened: my program tried f(x,y) where f = + and x an y are vectors. The program failed with the error msg: ERROR: MethodError: no method matching +(::String, ::String)
The problem is that x and y were vectors not strings.

S is defined as a Julia stack of any type.

pop() uses pop!(S), but first it ensures S is not empty, printing an error msg if it is.

jacli() is the name of the running program. The line **Julia jacli() should make that clear.

Here is a snippet of jacli output that shows + works fine for numeric literals, only failing for vector literals. jacl handles all literals identically.

julia> jacli()
jacl version 0.1

S: 4 5.0 +
S[9.0]: exit
ans = 9.0

I don’t know how to respond to this. Surely you must understand that the name of a program you have apparently written yourself tells us nothing?

Can you copy paste from inside your function the code that defines x and y and what happens to it before the error occurs?

2 Likes

instead of describing it in everyday language, would you mind copy pasting your code that defines jacli()

in your IDE (or any place you write) it should be something like this:

function jacli(arguments)
    # the function jacli
end

and also the pop() function you’re talking about

function pop()
    # the function pop
end

Not only is this incredibly helpful for anyone who wants to help you. In my experience the process of extracting a minimum example frequently uncovers absolutely embarrassing bugs or thought errors which I’m thankful that I don’t have to show the world.

9 Likes
# Stack Operations
# ================
S = Stack{Any}()	# define the stack vector
P = Queue{Any}()	# define the program queue
 
function pop()
	if length(S) > 0
		pop!(S)
	else
		printstyled("\npop: stack underflow\n", color = :red)
	end
end

function push(x)
	push!(S,x)
end

# jacl interactive mode
# ---------------------
function jacli()
	print("\njacl version $version\n----------------")
	empty!(S)
	a = true
	while a
		prompt()		
		makeP(readline())
		a = execute()
	end
end

# execute program P
# -----------------
function execute()
	for i = 1:length(P)				# process P
		term = dequeue!(P)
		if  isa(term,Number) ||		# is it a literal?
			isa(term,Bool)   
			push!(S,term)			# yes
			continue
		elseif isa(term,Function)||	# is it a function?
			term == dup  ||
			term == drop ||
			term == swap ||
			term == rot  ||
			term == under
			apply(term)				# yes
			continue
		elseif term == "exit"		# is it exit?	
			ans = pop()				# quit
			println("\nans = $ans\n")
			return false
		else 						# must be a quotation
			push!(S,term)
		end
	end	
	return true
end 		


# Apply the function f to the stack
# (S)f = S'
# ---------------------------------
function apply(f)
	ar = methods(f).ms[1].nargs-1		# get function arity
	if ar == 0	
		if f == dup   dup() end
		if f == drop  drop() end
		if f == swap  swap() end
		if f == rot   rot() end
		if f == under under() end
	end
	if ar == 1
		x = pop()
		push(f(x))
		return
	elseif ar == 2	
		x = pop()
		y = pop()
		push(f(x,y))
		return
	elseif ar == 3
		x = pop()
		x = pop()
		z = pop()
		push(f(x,y,z)) 
	end
end

The code is a bit difficult to follow, using global variables like this is not recommended. The important parts probably happen inside makeP, which I don’t think you posted.

But I see you are using readline to create some data structure, so my guess is that x and y are strings from the very beginning. We need to see exactly how they are created, but this:

is clearly wrong, if you print the string "[4,5,6]" it will look like this.

4 Likes

Could you also place the code within three backticks, like this? It will also appear neatly indented.
```
code here
```.

I think you’ve solved it. I was confused by thinking printing a string would show the quotes around it. Many thanks!

That still leaves me with a question I asked previously: how can I get [1,2,3] from “[1,2,3]”?
It seems I can print [1,2,3], but how can I assign it to a variable?

Conversely, is there a way to read a line of input from the console other than as a string?

I’ll remember this for next time, thanks.

Maybe parse.(Int, split(strip(str, ['[', ']']), ','))?

1 Like

No problem. Could you please edit your previous posts and apply the triple backticks? Other people may find this thread useful.

Thanks for the suggestion, but I don’t want to strip the brackets, I want to strip the quotes. I’ve tried stripping the quotes, but it doesn’t work.

Done!

1 Like

The output is a vector:

julia> parse.(Int, split(strip("[1,2,3]", ['[', ']']), ','))
3-element Vector{Int64}:
 1
 2
 3