diff --git a/pkg/JuliaInterface/gap/convert.gd b/pkg/JuliaInterface/gap/convert.gd
index 65e0e3df..aab9d196 100644
--- a/pkg/JuliaInterface/gap/convert.gd
+++ b/pkg/JuliaInterface/gap/convert.gd
@@ -205,24 +205,24 @@
#! UInt64,
#! UInt128,
#! BigInt,
-#! Rational{T} where T <: Integer,
+#! or Rational{T} where T <: Integer,
#!
#! -
#! GapObj and IsInt to
#! BigInt (default),
-#! Rational{T} where T <: Integer,
+#! or Rational{T} where T <: Integer,
#!
#! -
#! GapObj and IsRat to
#! Rational{BigInt} (default),
-#! Rational{T} where T <: Integer,
+#! or Rational{T} where T <: Integer,
#!
#! -
#! IsFloat to
#! Float16,
#! Float32,
#! Float64 (default),
-#! BigFloat,
+#! or BigFloat,
#!
#! -
#! IsChar to
@@ -254,12 +254,12 @@
#! Vector{Union{Any,Nothing}} (default),
#! Vector{T},
#! Matrix{T},
-#! T <: Tuple,
+#! or T <: Tuple,
#!
#! -
#! IsRecord to
-#! Dict{Symbol,Any} (default),
-#! Dict{Symbol,T}.
+#! Dict{Symbol,Any} (default)
+#! or Dict{Symbol,T}.
#!
#!
#!
@@ -271,16 +271,33 @@
#!
#! Conversion from &Julia; to &GAP;
#!
-#! The function
-#! is a &GAP; constructor taking two arguments,
-#! a &GAP; filter and an object to be converted.
+#! There are two alternatives for this direction,
+#! the Julia constructor
+#! and the &GAP; constructor
+#! .
+#!
+#! is a &Julia; function
+#! that takes one or two arguments,
+#! the object to be converted and optionally the value true
+#! indicating recursive conversion of nested objects.
+#! The chosen method depends on the &Julia; type of the first argument.
+#!
+#! The function .
+#! takes two or three arguments,
+#! a &GAP; filter and an object to be converted,
+#! and optionally the value true indicating recursive conversion
+#! of nested objects.
#! Various methods for this constructor then take care of input validation
#! and the actual conversion, either by delegating to the &Julia; function
#! julia_to_gap
-#! (which takes just one argument and chooses the &GAP; filters of its
-#! result depending on the &Julia; type),
+#! (which takes just one or two arguments and chooses the &GAP; filters of
+#! its result depending on the &Julia; type),
#! or by automatic conversion.
-#! The supported &Julia; types are as follows.
+#!
+#! The supported &Julia; types of the second argument of
+#!
+#! are as follows;
+#! more &Julia; types may be supported for .
#!
#!
#!
@@ -350,6 +367,46 @@
#! @Section Conversion functions
#! @SectionLabel Conversion_functions
+#!
+#!
+#!
+#!
+#! a &GAP; object
+#!
+#! The &Julia; constructor takes an object
+#! juliaobj and chooses a method depending on its &Julia; type
+#! for computing a &GAP; object corresponding to juliaobj.
+#! If recursive is true then nested objects are converted
+#! recursively.
+#!
+#!
+#!
+#!gap> Julia.GAP.Obj( 42 );
+#!42
+#!gap> m:= GAPToJulia( [ [ 1, 2 ], [ 3, 4 ] ] );
+#!<Julia: Any[Any[1, 2], Any[3, 4]]>
+#!gap> Julia.GAP.Obj( m );
+#![ <Julia: Any[1, 2]>, <Julia: Any[3, 4]> ]
+#!gap> Julia.GAP.Obj( m, true );
+#![ [ 1, 2 ], [ 3, 4 ] ]
+#!
+#!
+#! One advantage of compared to the &GAP;
+#! constructor is
+#! that it is easy to extend the scope of
+#! on the &Julia; side, whereas extending
+#!
+#! would require changing its methods.
+#! For example, the Oscar system provides &Julia; types
+#! of matrices for which conversions to &GAP; matrices are installed,
+#! via suitable methods for .
+#!
+#! If one is sure that the result of the conversion to &GAP; is not an
+#! immediate &GAP; object then one can call
+#! instead of .
+#!
+#!
#! @Arguments filt, juliaobj[, recursive]
#! @Returns a &GAP; object in the filter filt
@@ -361,6 +418,17 @@
#! Then
#! returns this &GAP; object.
#!
+#! @BeginExampleSession
+#! gap> s:= GAPToJulia( "abc" );
+#!
+#! gap> JuliaToGAP( IsString, s );
+#! "abc"
+#! gap> l:= GAPToJulia( [ 1, 2, 4 ] );
+#!
+#! gap> JuliaToGAP( IsList, l );
+#! [ 1, 2, 4 ]
+#! @EndExampleSession
+#!
#! For recursive structures (&GAP; lists and records),
#! only the outermost level is converted except if the optional argument
#! recursive is given and has the value true,
@@ -375,14 +443,12 @@
#! something useful on the &GAP; side.
#!
#! @BeginExampleSession
-#! gap> s:= GAPToJulia( "abc" );
-#!
-#! gap> JuliaToGAP( IsString, s );
-#! "abc"
-#! gap> l:= GAPToJulia( [ 1, 2, 4 ] );
-#!
-#! gap> JuliaToGAP( IsList, l );
-#! [ 1, 2, 4 ]
+#! gap> m:= GAPToJulia( [ [ 1, 2 ], [ 3, 4 ] ] );
+#!
+#! gap> JuliaToGAP( IsList, m );
+#! [ , ]
+#! gap> JuliaToGAP( IsList, m, true );
+#! [ [ 1, 2 ], [ 3, 4 ] ]
#! @EndExampleSession
#!
#! The following values for filt are supported.
diff --git a/pkg/JuliaInterface/tst/convert.tst b/pkg/JuliaInterface/tst/convert.tst
index 2400cc73..0d5b9a00 100644
--- a/pkg/JuliaInterface/tst/convert.tst
+++ b/pkg/JuliaInterface/tst/convert.tst
@@ -14,6 +14,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("Int64(123)");;
@@ -21,6 +23,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("Int32(123)");;
@@ -28,6 +32,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("Int16(123)");;
@@ -35,6 +41,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("Int8(123)");;
@@ -42,6 +50,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("UInt128(123)");;
@@ -49,6 +59,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("UInt64(123)");;
@@ -56,6 +68,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("UInt32(123)");;
@@ -63,6 +77,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("UInt16(123)");;
@@ -70,6 +86,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> x := JuliaEvalString("UInt8(123)");;
@@ -77,12 +95,16 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
#
gap> int := GAPToJulia( Julia.Base.Int64, 11 );
11
gap> JuliaToGAP(IsInt, int );
11
+gap> Julia.GAP.Obj( int );
+11
#
gap> x := JuliaEvalString("BigInt(123)");;
@@ -90,6 +112,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsInt, x);
123
+gap> Julia.GAP.Obj(x);
+123
###
### Floats
@@ -101,6 +125,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsFloat, x);
1.
+gap> Julia.GAP.Obj(x);
+1.
#
gap> x := JuliaEvalString("Float32(1.0)");;
@@ -108,6 +134,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsFloat, x);
1.
+gap> Julia.GAP.Obj(x);
+1.
#
gap> x := JuliaEvalString("Float16(1.0)");;
@@ -115,6 +143,8 @@ gap> typeof(x);
gap> JuliaToGAP(IsFloat, x);
1.
+gap> Julia.GAP.Obj(x);
+1.
###
###
@@ -127,16 +157,24 @@ gap> Zero(big2);
gap> JuliaToGAP( IsInt, Zero(big2) );
0
+gap> Julia.GAP.Obj( Zero(big2) );
+0
gap> ForAll([0..64], n -> JuliaToGAP( IsInt, big2^n) = 2^n);
true
+gap> ForAll([0..64], n -> Julia.GAP.Obj( big2^n ) = 2^n);
+true
gap> ForAll([0..64], n -> JuliaToGAP( IsInt, -big2^n) = -2^n);
true
+gap> ForAll([0..64], n -> Julia.GAP.Obj( -big2^n ) = -2^n);
+true
#
gap> string := GAPToJulia( Julia.Base.AbstractString, "bla" );
gap> JuliaToGAP( IsString, string );
"bla"
+gap> Julia.GAP.Obj( string );
+"bla"
gap> GAPToJulia( true );
true
gap> GAPToJulia( false );
@@ -147,6 +185,8 @@ gap> list:= GAPToJulia( [ 1, 2, 3 ] );
gap> JuliaToGAP( IsList, list );
[ 1, 2, 3 ]
+gap> Julia.GAP.Obj( list );
+[ 1, 2, 3 ]
## ranges
gap> Julia.GAP.julia_to_gap( JuliaEvalString( "1:3" ) );
@@ -155,6 +195,12 @@ gap> Julia.GAP.julia_to_gap( JuliaEvalString( "1:2:5" ) );
[ 1, 3 .. 5 ]
gap> Julia.GAP.julia_to_gap( JuliaEvalString( "3:2" ) );
[ ]
+gap> Julia.GAP.Obj( JuliaEvalString( "1:3" ) );
+[ 1 .. 3 ]
+gap> Julia.GAP.Obj( JuliaEvalString( "1:2:5" ) );
+[ 1, 3 .. 5 ]
+gap> Julia.GAP.Obj( JuliaEvalString( "3:2" ) );
+[ ]
gap> JuliaToGAP( IsList, JuliaEvalString( "1:3" ) );
[ 1 .. 3 ]
gap> JuliaToGAP( IsList, JuliaEvalString( "1:2:5" ) );
@@ -179,8 +225,12 @@ gap> emptystring:= GAPToJulia( Julia.Base.AbstractString, "" );
gap> JuliaToGAP( IsList, emptylist );
[ ]
+gap> Julia.GAP.Obj( emptylist );
+[ ]
gap> JuliaToGAP( IsString, emptystring );
""
+gap> Julia.GAP.Obj( emptystring );
+""
## 'GAPToJulia' for Julia functions (inside arrays)
gap> parse:= JuliaFunction( "parse", "Base" );
@@ -189,11 +239,15 @@ gap> list:= GAPToJulia( JuliaEvalString( "Vector{Any}"), [ 1, parse, 3 ] );
gap> list2:= JuliaToGAP( IsList, list );
[ 1, , 3 ]
+gap> Julia.GAP.Obj( list );
+[ 1, , 3 ]
##
gap> xx := JuliaEvalString("GAP.Globals.PROD(2^59,2^59)");;
gap> JuliaToGAP( IsInt, xx );
332306998946228968225951765070086144
+gap> Julia.GAP.Obj( xx );
+332306998946228968225951765070086144
###
### Records/Dictionaries
@@ -204,6 +258,8 @@ gap> dict:= GAPToJulia( rec() );
gap> JuliaToGAP( IsRecord, dict );
rec( )
+gap> Julia.GAP.Obj( dict );
+rec( )
## nested record: non-recursive vs. recursive
gap> dict:= GAPToJulia( rec( bool:= true,
@@ -212,8 +268,12 @@ gap> dict:= GAPToJulia( rec( bool:= true,
> ) );;
gap> JuliaToGAP( IsRecord, dict );
rec( bool := true, list := , string := )
+gap> Julia.GAP.Obj( dict );
+rec( bool := true, list := , string := )
gap> JuliaToGAP( IsRecord, dict, true );
rec( bool := true, list := [ 1, 2, 3 ], string := "abc" )
+gap> Julia.GAP.Obj( dict, true );
+rec( bool := true, list := [ 1, 2, 3 ], string := "abc" )
## something where recursive conversion would run into a Julia error
gap> dict:= GAPToJulia( rec( juliafunc:= Julia.Base.map,
@@ -221,6 +281,8 @@ gap> dict:= GAPToJulia( rec( juliafunc:= Julia.Base.map,
map)>
gap> JuliaToGAP( IsRecord, dict );
rec( juliafunc := )
+gap> Julia.GAP.Obj( dict );
+rec( juliafunc := )
# iterating over dict gives key-value pairs
gap> dict:= GAPToJulia( rec( a := 1, b := 2 ) );
@@ -230,4 +292,4 @@ Pair{Symbol, Any}(:a, 1)
Pair{Symbol, Any}(:b, 2)
##
-gap> STOP_TEST( "convert.tst", 1 );
+gap> STOP_TEST( "convert.tst" );
diff --git a/src/types.jl b/src/types.jl
index 0213aa22..6a06d37b 100644
--- a/src/types.jl
+++ b/src/types.jl
@@ -91,8 +91,9 @@ However, this is restricted to outputs that actually are of type `GapObj`.
To also deal with GAP integers, finite field elements and booleans, use
[`GAP.Obj`](@ref) instead.
-The keyword argument `recursive` with value `true` can be used to force
-recursive conversion of nested Julia objects (arrays, tuples, dictionaries).
+Recursive conversion of nested Julia objects (arrays, tuples, dictionaries)
+can be forced either by a second agument `true`
+or by the keyword argument `recursive` with value `true`.
# Examples
```jldoctest
@@ -105,6 +106,9 @@ GAP: [ [ 1, 2 ], [ 3, 4 ] ]
julia> GapObj([[1, 2], [3, 4]])
GAP: [ , ]
+julia> GapObj([[1, 2], [3, 4]], true)
+GAP: [ [ 1, 2 ], [ 3, 4 ] ]
+
julia> GapObj([[1, 2], [3, 4]], recursive=true)
GAP: [ [ 1, 2 ], [ 3, 4 ] ]
@@ -124,8 +128,9 @@ Moreover, it can be used as a constructor,
in order to convert Julia objects to GAP objects,
whenever a suitable conversion has been defined.
-The keyword argument `recursive` with value `true` can be used to force
-recursive conversion of nested Julia objects (arrays, tuples, dictionaries).
+Recursive conversion of nested Julia objects (arrays, tuples, dictionaries)
+can be forced either by a second agument `true`
+or by the keyword argument `recursive` with value `true`.
# Examples
```jldoctest
@@ -138,12 +143,14 @@ GAP: [ [ 1, 2 ], [ 3, 4 ] ]
julia> GAP.Obj([[1, 2], [3, 4]])
GAP: [ , ]
+julia> GAP.Obj([[1, 2], [3, 4]], true)
+GAP: [ [ 1, 2 ], [ 3, 4 ] ]
+
julia> GAP.Obj([[1, 2], [3, 4]], recursive=true)
GAP: [ [ 1, 2 ], [ 3, 4 ] ]
julia> GAP.Obj(42)
42
-
```
"""
const Obj = Union{GapObj,FFE,Int64,Bool}
diff --git a/test/constructors.jl b/test/constructors.jl
index ff376c3f..c442d19e 100644
--- a/test/constructors.jl
+++ b/test/constructors.jl
@@ -1,6 +1,6 @@
@testset "conversion from GAP using constructors" begin
- ## Analogous tests for conversion using convert are in convert.jl.
+ ## Analogous tests for conversion using convert are in conversion.jl.
@testset "Conversion to GAP.Obj and GAP.GapObj" begin
x = GAP.evalstr("2^100")
@@ -9,6 +9,19 @@
x = GAP.evalstr("Z(3)")
@test GAP.Obj(x) == x
@test GAP.Obj(0) == 0
+
+ # recursive conversion of nested objects
+ m = [[1, 2], [3, 4]]
+ c = GAP.Obj(m)
+ @test c[1] isa Vector
+ @test c == GAP.Obj(m, false)
+ c = GAP.Obj(m, true)
+ @test c[1] isa GAP.Obj
+ c = GAP.GapObj(m)
+ @test c[1] isa Vector
+ @test c == GAP.GapObj(m, false)
+ c = GAP.GapObj(m, true)
+ @test c[1] isa GAP.GapObj
end
@testset "Border cases" begin