Can I build an array using the Field command?

I want to create a series of arrays based on data in various Fields.

For example PackageType , the third field in my fourth table.

So my code is:

`BUILDARRAYS(“Type”;4)

ARRAY TEXT (<>aPackageType;0)

ARRAY POINTER ($Field;0)

$a := Get pointer ("<>aPackage"+ $1 ) `$1 is Type in this example

$Field := Field ( $2 ;2) `$2 is 4 in this example.

ALL RECORDS ( Table ( $2 ) » )

SELECTION TO ARRAY ( $Field» ; $a» )

But of course, that won’t work.

What have I missed?

Hi Sean,
it would be useful to know more about what “doesn’t work”. At 1st glance, the $Field seems OK (you can check in debugger), I’d suspect $a and BUILDARRAYS: what happens in it?

Here’s a method to test if an array is a one dimensional array, and optionally, of a given type:

  //Ptr_isArray (aPointer_p {;type_l {;type2_l {.. ;typeN_l) -> bool
  //$0 True if aPointer_p is a one dimensional array
  //$2..$N option : array type(s) to filter (use 4D constant)
C_BOOLEAN($0)
C_POINTER($1)
C_LONGINT(${2})

C_BOOLEAN($isArray_b)
C_LONGINT($i_l)
C_LONGINT($params_l)
C_LONGINT($type_l)

If (False)
	C_BOOLEAN(Ptr_isArray ;$0)
	C_POINTER(Ptr_isArray ;$1)
	C_LONGINT(Ptr_isArray ;${2})
End if 
  //_
$isArray_b:=False
$params_l:=Count parameters
If (Asserted($params_l>0;Current method name+" $1 missing"))
	If (Is a variable($1))
		C_COLLECTION($type_c)
		$type_c:=New collection(\
		Boolean array;Integer array;LongInt array;\
		Real array;Date array;Time array;\
		String array;Text array;Picture array;\
		Object array;Picture array;Pointer array)
		$type_l:=Type($1->)
		$isArray_b:=($type_c.indexOf($type_l)>=0)
		  //??? 26=tableau entier64 ???
		If ($isArray_b) & ($params_l>1)  //check the type too
			$i_l:=2
			Repeat 
				$isArray_b:=($type_l=${$i_l})
				$i_l:=$i_l+1
			Until ($i_l>$params_l) | ($isArray_b)
		End if 
	End if 
End if 
$0:=$isArray_b

I’d use it to investigate $a, something like:

$a:=Get pointer ("<>aPackage"+ $1 ) `$1 is Type in this example
ASSERT(Ptr_isArray($a);"not an array")
ASSERT(Ptr_isArray($a; $1);"not an array or not expected type")

Thanks Arnaud.

My method works uncompiled as is, but will not compile.
The line: $Field:= Field ( $2 ;2)
trips ‘Cannot make an assignment with those types

Here is the entire method:

  //ListBuild ("Size";3)
C_LONGINT($2)

If (Count parameters=2)  // Bag related
	
	$a:=Get pointer("<>aBag"+$1)
	$aID:=Get pointer("<>aBag"+$1+"ID")  //these were declared in STARTUP method
	
	$Field:=Field($2;2)  // the issue here is 2;2 is Text in every case EXCEPT bagSize...
	$FieldID:=Field($2;1)
	
	ARRAY POINTER($Field;0)
	ARRAY POINTER($FieldID;0)
	
	ALL RECORDS(Table($2)->)
	
	SELECTION TO ARRAY(Field($2;2)->;$a->;Field($2;1)->;$aID->)
	
	SORT ARRAY(Get pointer("<>aBag"+$1)->;Get pointer("<>aBag"+$1+"ID")->)
	
	
Else   //non bag lists
	
	$Title:=Get pointer("<>a"+$1)
	$ID:=Get pointer("<>a"+$1+"ID")
	$Field:=Field($2;2)
	$Field2:=Field($2;1)
	
	ARRAY TEXT($Title->;0)
	ARRAY LONGINT($ID->;0)
	ARRAY POINTER(aField;0)
	ARRAY POINTER(aField2;0)
	
	ALL RECORDS(Table($2)->)
	
	SELECTION TO ARRAY($Field->;$Title->;$Field2->;$ID->)
	
	SORT ARRAY(Get pointer("<>a"+$1)->;Get pointer("<>a"+$1+"ID")->)
	
End if 

Hi Sean,

You have defined $Field as an array of pointers but you are assigning it the value returned by Field which is a pointer (not an array).

4D doesn’t complain in interpreted mode because you can change the type of a variable, but compiled you can’t. The compiler is detecting that you are trying to assign a pointer to something that you have told it is an array.

Maybe remove the lines that are typing $Field and $FieldID as arrays? You don’t appear to use them as arrays anywhere.

You should also be able to merge a lot of that code. It appears that the only difference between the If and the Else is whether the interprocess arrays have the word ‘Bag’ in them. I’m not sure how you are getting into the Else block though - I assume you are passing a 3rd parameter that you aren’t using?

  //ListBuild ("Size";3)
C_TEXT($1)
C_LONGINT($2)

If (Count parameters=2)  // Bag related
	$a:=Get pointer("<>aBag"+$1)
	$aID:=Get pointer("<>aBag"+$1+"ID")  //these were declared in STARTUP method
Else   //non bag lists
	$a:=Get pointer("<>a"+$1)
	$aID:=Get pointer("<>a"+$1+"ID")
End if 

$Field:=Field($2;2)
$FieldID:=Field($2;1)

ALL RECORDS(Table($2)->)

SELECTION TO ARRAY($Field->;$a->;$FieldID->;$aID->)

SORT ARRAY($a->;$aID->)

Thanks Adam.

@Adam_Storck
Thanks!
@Nolen.Sean
Using code with pointers is sometimes difficult to debug. I often use some “what is pointed” functions (code examples here) for that purpose. Typical use:

//MyMethod (aField_p;anArray_p)
c_pointer($1;$2)
assert(count parameter=2)
assert(Ptr_isField($1);"$1 must be a field")
assert(Ptr_isArray($2);"2 must be an array")
assert(Ptr_isField($1;is longint);"$1 must be a longint field")
assert(Ptr_isArray($2;array longint);"$2 must be longint array")

BTW, I often hear people saying “assertions are useless”, my answer is always “then error messages in 4D commands are useless too”.

1 Like

Using code with pointers is sometimes difficult to debug.

Absolutely. Pointers can make generic code easier, but you have to accept the risk that your method might receive a bad pointer.

I like that “what is pointed” idea too.

My bad, I reversed the recipients: thanks was for you, remarks about pointer use for Sean.
Corrected in post above.

Ha ha … all good :smile: