How to overload convert - type-conversion

I have two types A and B. I have written B(a::A) and convert(::Type{B}, a), but this does not immediately make Array{B}(as::Array{A}) work. Must I write this method as well? According to
the documentation, I would expect Julia would handle the rest for me.
struct A end
struct B end
B(a::A) = B();
convert(::Type{B}, a) = B(a);
# These work
B(A());
convert(B, A());
# This doesn't
Array{B}([A()]);
This is the error
ERROR: LoadError: MethodError: Cannot `convert` an object of type A to an object of type B
Closest candidates are:
convert(::Type{T}, !Matched::T) where T at essentials.jl:154
B(::A) at /home/mvarble/test.jl:3
Stacktrace:
[1] setindex!(::Array{B,1}, ::A, ::Int64) at ./array.jl:767
[2] copyto! at ./abstractarray.jl:753 [inlined]
[3] copyto! at ./abstractarray.jl:745 [inlined]
[4] Type at ./array.jl:482 [inlined]
[5] Array{B,N} where N(::Array{A,1}) at ./boot.jl:427
[6] top-level scope at none:0
[7] include at ./boot.jl:326 [inlined]
[8] include_relative(::Module, ::String) at ./loading.jl:1038
[9] include(::Module, ::String) at ./sysimg.jl:29
[10] exec_options(::Base.JLOptions) at ./client.jl:267
[11] _start() at ./client.jl:436

You have to add a method to convert from Base, and not define a new convert function in the current module. Therefore you should write:
Base.convert(::Type{B}, a) = B(a)
or
import Base: convert
before defining convert as you did in your code.

Related

Invalid assignment error inside Julia macro

I was following along this notebook (originally written in Julia 0.x, I am using Julia 1.7.1). One of the cells defines the following macro.
macro twice(ex)
quote
$ex
$ex
end
end
On the very next cell, this macro is invoked.
x = 0
#twice println(x += 1)
Replicating this in the REPL (for brevity) results in the following error.
ERROR: syntax: invalid assignment location "Main.x" around REPL[1]:3
Stacktrace:
[1] top-level scope
# REPL[4]:1
So, I understand that x += 1 is somehow causing this problem, but after going through the docs (metaprogramming), I could not figure out why exactly this is an invalid assignment or how to fix this.
#macroexpand #twice println(x += 1) successfully returns the following.
quote
#= REPL[1]:3 =#
Main.println(Main.x += 1)
#= REPL[1]:4 =#
Main.println(Main.x += 1)
end
So, I tried evaling this in the top-level without the Main.s, and it evaluates successfully.
x = 0
eval(quote
println(x += 1)
println(x += 1)
end)
Output:
1
2
But, if I add the module name explicitly, it throws a different error.
eval(quote
Main.println(Main.x += 1)
Main.println(Main.x += 1)
end)
ERROR: cannot assign variables in other modules
Stacktrace:
[1] setproperty!(x::Module, f::Symbol, v::Int64)
# Base ./Base.jl:36
[2] top-level scope
# REPL[14]:3
[3] eval
# ./boot.jl:373 [inlined]
[4] eval(x::Expr)
# Base.MainInclude ./client.jl:453
[5] top-level scope
# REPL[14]:1
I tried a few other things, but these are the only things that I think might be getting somewhere.
Why exactly is the assignment in the first macro code block invalid? Is it for the same reason that evaling in the top-level with the module Main specified fails?
How can this invalid assignment be circumvented, OR how do I port this to Julia 1.7?
Use esc (This "prevents the macro hygiene pass from turning embedded variables into gensym variables"):
julia> macro twice(ex)
esc(quote
$ex
$ex
end)
end;
julia> x=1
1
julia> #twice println(x += 1)
2
3

Cannot `convert` an object of type BitArray{1} to an object of type Int64. Julia

I am very new in Julia, so maybe it is stupid question. I have the following code:
a = [1.0, 2.0];
b = [2.2, 3.1];
Int(a.>b)
It gives me an error:
MethodError: Cannot `convert` an object of type BitArray{1} to an object of type Int64
This may have arisen from a call to the constructor Int64(...),
since type constructors fall back to convert methods.
Stacktrace:
[1] Int64(::BitArray{1}) at ./sysimg.jl:77
[2] include_string(::String, ::String) at ./loading.jl:522
The command 1(a.>b) works well.
Could You explain me:
Why my implicit conversion did not work?
a.>b is of type BitArray{1}. With Int(a.>b) you are trying to convert an array, namely a BitArray, to a single integer, which doesn't make sense.
Instead you probably want to convert the elements of the array to integers:
julia> a = [1.0, 2.0];
julia> b = [2.2, 3.1];
julia> Int.(a.>b)
2-element Array{Int64,1}:
0
0
Note the dot in Int.(a.>b) which broadcasts the conversion to every element.
The reason why 1(a.>b) works is because it is being translated to 1*(a.>b). This is a multiplication of a number and an array which is an element-wise operation.

How to add element to cell array including case it is empty?

Is it possible to add element to cell array including case when it is currently empty and or not exist?
All of these methods work
>> C={12}
C =
[12]
>> C=[C;13]
C =
[12]
[13]
>> C{end+1}=14
C =
[12]
[13]
[14]
But all of them require C exists.
Neither work if C does not exist. Is it possible to do so?

How to add rows in between cell array in Matlab?

I have two cell arrays.
A(290*6) and B(300*6);
First column in two arrays are identical. I compared first column of two cell arrays using 'ismember'. I want to do that ; where cell elements are missing in cell array(A), I have to add a row where element is missing. Is it possible in Matlab?
It's not easy to insert rows into an existing matrix or cell array; it's easier to construct a new one and fill it appropriately.
Find the locations of the contents of the first column of A in the cell array B:
[aa,bb] = ismember([A{:,1}],[B{:,1}]);
Create a new empty cell array:
C = cell(length(B),size(A,2))
Fill it:
C(:,1)=B(:,1)
C(bb,2:end) = A(aa,2:end);
For example, given this A ("3" row missing)
[1] [3]
[2] [5]
[4] [3]
And this B:
[1]
[2]
[3]
[4]
This returns:
[1] [3]
[2] [5]
[3] []
[4] [3]
To fill the empty spaces with the previous row (this will only work if the empty rows are non-consecutive and the first row of C is non-empty):
n = setdiff(1:length(C),bb)
C(n,2:end) = C(n-1,2:end);
I think you can directly use the second output of setdiff
[d,i] = setdiff(B(:,1),A(:,1))
i will tell you where the rows in A are that are missing.

Is there a way to determine exactly what operator a Perl B::LOGOP object refers to?

From playing with B, I see that a B::LOGOP object (call it "$op") referring to either a && or and operator will both return "and" upon calling $op->name. Is it possible to determine which operator the LOGOP refers to merely by examining $op?
I am not expert for perl internals, but LOGOP refers to logical operator group. So I don't think you can know individual operator without examining the name. Even B::Terse displays it:
perl -MO=Terse -e '$a && $b'
Shows:
....
LOGOP (0x198ad94) and
UNOP (0x198adec) null [15]
PADOP (0x198ae08) gvsv GV (0x187bb9c) *a
UNOP (0x198adb4) null [15]
PADOP (0x198add0) gvsv GV (0x187bc9c) *b