constant array of strings?

I have a bunch of constants defined as strings in a module.

Apple = “Apple”
Banana = “Banana”
Cantaloupe = “Cantaloupe”

I want to make an array that is immutable called fruit
Fruit = {Apple, Banana, Cantaloupe}

How do I define the Fruit array?

You can’t in the strict sense of your question. The closest you can come is to create a method that returns a string array, something like this:

Function FruitArray () As String()
  return array( Apple, Banana, Cantaloupe )
End Function

But nothing will stop you from doing this:

dim arr() as string = FruitArray
arr.Append "Anvil"

But at least FruitArray will be the same the next time it is accessed directly.

You could create a custom class that behaves like a string array but has no Append method as well.

If you code this as a class or a method how does this for loop behave?

for f as string in m.FruitArray ... next
Is this going to reconstruct FruitArray on every iteration of the for loop?

Theoretically if FuitArray isn’t a constant but is a method or a mutable array, then the contents and size of the array can change between iterations of the for loop. I mean we code to avoid these things and we know that we won’t change them, but the language isn’t giving me an immutable constant array.

dim a(-1) as string = m.FruitArray // is this a bunch of string copies? for f in a ... next

This seems safer but… is the contents of the array duplicated because we are talking about string objects. i.e. not really fast or optimal.

You can add the Iterable interface for for-each loops. http://developer.xojo.com/xojo-core-iterable

See my attempt at a constant string class here… https://forum.xojo.com/conversation/post/262227

[quote=269122:@Will Shank]You can add the Iterable interface for for-each loops. http://developer.xojo.com/xojo-core-iterable

See my attempt at a constant string class here… https://forum.xojo.com/conversation/post/262227[/quote]

I didn’t see your post the first time around. Your class should only implement Iterable and have a separate iterator class.

No.

Yes.

One clarification here:

dim s1 as string = "hi"
dim s2 as string = s1
dim s3 as string = s1

That code has created one string with three references to it. The string was not copied.

Why a separate class? Would a separate instance be enough for whatever the issue is?

[quote=269126:@Kem Tekinay]One clarification here:

dim s1 as string = "hi"
dim s2 as string = s1
dim s3 as string = s1

That code has created one string with three references to it. The string was not copied.[/quote]
True, but

dim a1() as string = m.FruitArray
dim a2() as string = m.FruitArray
dim a3() as string = m.FruitArray

could, assuming the correct implementation of FruitArray, yield 3 copies of the strings.

But string isn’t a class it’s a type. Doesn’t that matter?

dim i1 as integer = 1
dim i2 as integer = i1

modifying i2 doesn’t change i1.

[code]Module FruitModule

Private Function GetFruitInstance() As Fruit
Static ti As Introspection.TypeInfo = GetTypeInfo(Fruit)
Static cis() As Introspection.ConstructorInfo = ti.GetConstructors()
Static ci As Introspection.ConstructorInfo = cis(0)
Static f As Fruit = ci.Invoke()
Return f
End Function

Global Function Fruit() As Fruit
Return GetFruitInstance()
End Function

Global Function Fruit(index As Integer) As String
Static f As Fruit = GetFruitInstance()
Return f(index)
End Function

Global Class Fruit
Implements xojo.Core.Iterable

Protected Sub Constructor()
// Fruit cannot be instantiated from outside this module
End Sub

Function GetIterator() As Xojo.Core.Iterator
Return New FruitIterator(Self)
End Function

Function Operator_Subscript(index As Integer) As String
Static items() As String = Elements
Return items(index)
End Function

Protected Shared Function Elements() As String()
Return Array(“Apple”, “Banana”, “Cantaloupe”)
End Function

Shared Function IndexOf(item As String) As Integer
Return Elements.IndexOf(item)
End Function

Shared Function Ubound() As Integer
Return Elements.Ubound
End Function

End Class

Private Class FruitIterator
Implements xojo.Core.Iterator

Private Dim mElements As Fruit
Private Dim mIndex As Integer = -1

Sub Constructor(elements As Fruit)
mElements = elements
End Sub

Private Function MoveNext() As Boolean
If mIndex >= mElements.Ubound Then
Return False
Else
mIndex = mIndex + 1
Return True
End
End Function

Private Function Value() As Auto
Return mElements(mIndex)
End Function

End Class

End Module[/code]

[code]// Get an item by index
Dim item1 As String = Fruit(1)
System.DebugLog item1

// Get upper bound
Dim ub As Integer = Fruit.Ubound
System.DebugLog Str(ub)

// Get the index of an item
Dim index As Integer = Fruit.IndexOf(“Banana”)
System.DebugLog Str(index)

// For loop
For i As Integer = 0 To Fruit.Ubound
System.DebugLog Fruit(i)
Next

// For Each loop
For Each item As Auto In Fruit
System.DebugLog CType(item, String)
Next[/code]

[quote=269138:@Brian O’Brien]But string isn’t a class it’s a type. Doesn’t that matter?

dim i1 as integer = 1
dim i2 as integer = i1

modifying i2 doesn’t change i1.[/quote]
Strings are immutable. So they don’t have to be copied until you modify one.

dim s1 as string = "abc"
dim s2 as string = s1
// you have a single string with 2 references
s2 = s2 + "d"
// now you have 2 separate strings

Strings act like the integers in your example, but as an implementation detail, they try to conserve space by not making an extra copy if they don’t have to. They’re an intrinsic type, but they have some characteristics of a class.

[quote=269119:@Brian O’Brien]If you code this as a class or a method how does this for loop behave?

for f as string in m.FruitArray ... next
Is this going to reconstruct FruitArray on every iteration of the for loop?[/quote]

‘m.FruitArray’ will only be evaluated once, at the beginning of the loop.

If ‘FruitArray’ were implemented as in Kem’s first post, there’s no need to worry about this.

You can have multiple iterators created from the same iterable. Returning the same object from GetIterator causes moving one iterator forward to affect the ‘other’ ones.

[quote=269137:@Tim Hare]True, but

dim a1() as string = m.FruitArray
dim a2() as string = m.FruitArray
dim a3() as string = m.FruitArray

could, assuming the correct implementation of FruitArray, yield 3 copies of the strings.[/quote]

That would create three distinct arrays, but the strings within each would be the same, that is, not copies. In this respect, Strings behave much like objects.

@Eli Ott Thanks. That was a lot of work. Love that username :slight_smile:

Et all thank you too.

hmm…
had a thought…

private const pseudoArray="A,B,C" Sub Operator Subscript(index as integer) return Split(pseudoArray, ",")(index) End

[quote=269216:@Brian O’Brien]hmm…
had a thought…

private const pseudoArray="A,B,C" Sub Operator Subscript(index as integer) return Split(pseudoArray, ",")(index) End[/quote]

This has a much higher performance cost than returning the result of the Array() operator.

By golly, you’re right. I thought I had tested that out before, but I just ran some tests and it does appear that the framework is smart enough to reuse the string literals.