Issues with creation

No. I dont meant the whole “God created the earth in 7 days” business. Sorry but this isnt going to be a discussion of monotheism and the belief systems they have. Maybe some other time when I get tired of discussing it with my uncle, the ex-Catholic priest, and his wife, the ex-Catholic nun. It does make for some fun discussions though 🙂

No, this is about the whole question of creating objects in Xojo and how, in our code, we can make it so some code can create new instances using NEW and other code cannot.

This pattern occurs frequently in Xojo.

Pictures can create and return Graphics objects but we cannot use NEW to create one. Queries of database objects can create & return RecordSets, but we cant create one using NEW.

So how can we accomplish this in our own code ? If we should not be creating new instances using NEW it would be nice to have the compiler help us enforce that rule. Its easy to make it so we can NOT use NEW by adding private or protected constructors. But then NO code can create a new instance. And thats not quite what we want. We want it so most code cannot create new instances, but a VERY limited set can.

In many cases some will just suggest that you do this “by convention”. All this means is “dont do that when you shouldn’t”. Its nothing the compiler helps enforce. You just dont write code that uses new with certain classes. Doing things “by convention” is often error prone. And the compiler doesnt help us at all in these cases.

Personally I don’t like things that the compiler could help me with that aren’t designed in a way that it CAN help me with. And this is one where we absolutely can design code that the compiler can help us with.

In some languages you can nest classes inside others. By doing this you can limit what is exposed in the classes that are embedded in the others. Xojo doesn’t have any means of doing this.1 So we need some other mechanism.

In some cases in Xojo you can use an interface to hide certain details from other classes. But if the interface is globally accessible then every other bit of code can still use that interface to manipulate the classes that implement it. And an interface can’t be used to create new instance so using one doesn’t seem like it will work very well.

What we need is a way to have a globally accessible class that effectively has no, or only private constructors, the some code can call to create new instances.

Lets mimic Picture and Graphics as our example. We want to work towards the same goal of making it so the compiler disallows

New Graphics

but allows

dim g as Graphics = Picture.Graphics

Lets start with putting all this in a module. We’ll call it PictureMimicry. And in that module we’ll add two classes – MyPicture And MyGraphics.

We’ll add a method to MyPicture, MyGraphics, that returns a MyGraphics object.2

Function MyGraphics() as MyGraphics
End Function     

Make sure that the scope property of MyPicture and MyGraphics are both global so you can use their names anywhere without having to qualify them with the module name.

Now in our App.open event we could write

dim p as MyPicture
dim g as MyGraphics

p = new MyPicture

but, we could also add

g = new MyGraphics

and this is what we want the compiler to catch for us and tell us this is not allowed.

You might be asking “Why the heck did we put all this in a module then make everything global?” And, it turns out that everything being in a module is part of how we can make everything work the way we want.

When you put code, classes, etc in a module you can set a Scope property on those items. And one of the scope settings is Private. What this means is that no code outside the module can access these items, but things INSIDE the module can. So how does that help us ?

At first you might think “Oh great I’ll put a private constructor on the MyGraphics class and that will solve things”. But it doesn’t. That constructor is then PRIVATE to the MyGraphics class and nothing else call it. Not even code in the module can use it.

So how then do we create new instances of the MyGraphics class, make it so only code IN the module or in other classes in the module can create new instances, and any code outside the module can not ?

This is absolutely possible.

Maybe I should leave off here and let you all ponder this for a while and then follow up with the answer in another blog post. Replies are welcome as to how you think we do this.

  1. I’m told by ex-compiler engineers that the compiler could handle this BUT its not exposed in any way in any portion of the language or the IDE.
  2. We could have used a computed property and only implemented the getter just as easily. Either works.

Why implicit instance isnt your friend

When you start a new desktop project in Xojo you get a few items by default.

One of the is a Window – often named Window1.

And it has a certain set of default properties. One of these causes a LOT of confusion and grief. You end up with issues like Window opening unexpectedly, Mac Window Size Keep Changing and Enumerations act private when they are not

While at first implicit instance makes life simple once you get very far with Xojo it becomes a liability. It can be come an impediment to writing code.

And the reason is that just by using the name of the window you actually run a method that will, if one doesnt already exist, create a new instance of the window. And this can block you from being able to access some things that are defined on that window.

Enumerations are one that it definitely causes issues with. There may be others as I havent tested everything.

So, if you dont use implicit instance what DO you use ?

To create a new instance you use NEW. Just like you do with any other class.

And if you dont want to create one IF one already exists then you can actually see if any other windows that are open ARE a Window1 and use that one.

Implicit instance saves you writing about 10 lines of code. And causes even long time users no end of problems. In fact I know some users that have gone so far as to define their own templates for projects and have set the default Window1 to not have implicit instance on. But that only affects that first windows and any others inserted will still have it enabled.

You can turn it off for ALL of the new ones you add to a projects by altering the default values for certain properties using the Overrides system. This makes it possible for you to make it so NO new windows added have implicit instance turned on.

Talking about other tools

One thing thats not usually allowed on Xojo’s forums is talk about other products that they might consider “competitors”

But there are some interesting options and discussion of them can take place on the user group hosted forums at IfNotNil.Com

You might want to give them a try

Operator_convert

In a recent discussion on the forums someone said that “operator_convert acts like a constructor”.

It’s true, except when its not.

For instance, if you create a class that has an “operator_convert from” then you may be surprised at the behaviour.

So first, whats an “operator_convert from” ?

A class can have two forms of operator_convert. One takes a parameter. And one doesnt. For instance if I have a class, Box, that can be created from a string there are several ways to do this.

You might write one that is a constructor that takes a string that holds the top, left, width and height

Sub Constructor(constructFromString as String)

But then your code has to do something like

Dim b as new Box( "0,0,10,10" )

But this isnt always quite as convenient as we’d like. One other option is to provide the “operator_convert from” form of Operator_convert. That would be a nethod you add that looks like

Sub operator_convert(constructFromString as String)

And this form lets you write code that looks like

Dim b as Box =  "0,0,10,10" 

This appears a little nicer. So yes, in this case operator_convert from acts a LOT like a constructor.

However, if your constructor sets some internal state that the instance requires note that Operator_Convert does NOT call the constructor at all.

You can see this in action if, in th case of the Box class above, we put a break statement in the Constructor and then use the operator_convert from form.

Class Box
   Sub Constructor(constructFromString as string)
     break
   End Sub
   Sub Constructor()
     break
   End Sub
   Sub Operator_convert(constructFromString as string)
   End Sub
End Class

dim b as Box = "10,10,50,50"

You’ll find that you DO get a new instance BUT neither constructor is called. so IF you rely on the fact that your constructor HAS configured some properties in a particular way you might need to manually call the constructor yourself in the Operator_Convert from Form.

You can overload operator_convert from and convert from as many types as you want for your. needs

The second form of operator_convert is the “operator_convert to” form. This one is code you can use to take a custom class and return a different representation of the class..You might want to return it as a string, a double, or just about any other form you might need.

In our box example above the operator_convert to form might return a string. It might look like

Sub operator_convert() as String

Note this form never takes a parameter. And you can have as many as you want as long as they do not cause any ambiguity. If you add one that converts to integer then don’t try and add one for int32 and int64 since integer is either an int32 or and int64 as you will get compilation errors.

Both forms of operator_convert are VERY handy.

This one might surprise you

Lets start with the code

Dim v1 As Variant = Nil
Dim v2 As Variant = 12

If v1 < v2 Then
  Break
Elseif v2 < v1 Then
  Break
End If

Which break statement would YOU expect to be hit ? I will say that the one that does get hit here is NOT what I expected at all.

When you compare variants they convert to a common type. Not sure that I know what the common type that would be used is here.

It doesnt appear to be any of the numeric types.

And the comparison doesn’t seem to be relying on the hash value of a variant.

If you add in code to explicitly convert each variant to some other type (Uint64, int64, Object, String, etc) you see that those all have a nil variant being treated as if its 0 and the non-nil variant as if they are the numeric value.

Developers needs are not the same as consumers needs

There are lots of apps; desktop, web, and mobile. And they are for all kinds of needs for general consumption.

Developers needs often don’t fit that model though.

How many developers have IDE’s that the use on the Web ? Or on their mobile phone ? You might be able to write text there but if you using a tool like VS Code, Xcode, etc these are still mostly traditional desktop apps.

And this is where tool vendors often fall down. There are many who say “Hey use our tools you can write macOS, Windows, Linux, mobile, iOS and all kinds of other apps with our tool !” And, as Bob found, this is often like chasing unicorns.

I’ve spent a couple days on the phone with one tool vendor whose answer is “well just use Windows to write your macOS, Linux and Windows apps” To me this makes no sense. If your tool can create applications for macOS isnt the tool written using itself ? And if so then where is the macOS version of the tool since you claim you can write macOS apps. Or the Linux one for the same reason.

There are several tools like this where they claim you can create apps for all sorts of targets BUT you can only use the tool on one of the targets tat are supported. Which tells me that their tool is not written using their tool. If they wont use it to write their tool how can I be sure I can write what I need with their tool ?

While I might be critical of Xojo fairly often ONE thing they do is dog-fooding. They use their tool to create their tool.(1) Bugs in their framework show up in their faces and they have incentive to fix them because otherwise THEY see the bug all the time.

I wish more tool vendors did this.

footnotes

(1) Xojo does a reasonable job of dog-fooding but there are aspects of the framework that are not used in the IDE so they dont dog-food everything as thoroughly as we might like.

Ch-ch-ch-changes

In the world somethings change and some don’t. Some change loudly. Some things change quietly and invisibly.

One that I’m disappointed that has changed kind of quietly is Bob Keeney’s role in the community. Apparently he’s no longer a Xojo consultant.

Its notable that after nearly 20 years as a REALbasic/Xojo consultant Bob has moved into a new role at BlackBag Technologies. Probably not a bad move for him but still a significant change in the community.

Personally I have a pretty good idea what transpired to lead to this change. And while I might be disappointed things culminated in Bob taking a role there I also understand the motivation.

I have no idea if his new role will have him using Xojo or not.

But, the community has lost one of the better examples of building a consultancy using Xojo. Thats disappointing.

I wish him nothing but the best and all the success in the world in his new role.

Is nil or = nil ?

Often in code you might see checks for NIL written as

if foo = nil then

and sometimes you might see

if foo is nil

Whats the difference between the two ?

In Xojo the IS operator compares the references. It doesn’t compare the contents of the objects in any way. It answers the question “do these two references refer to the exact same instance” – in some languages this would be comparing whether two pointers point to the same location.

= will do much the same IF you have NOT implemented operator_compare for your specific classes. However if you HAVE implemented operator_compare then you can get VERY different results as your implementation of operator_compare will be called, even if one of the items is nil. In the following code

if foo = nil then

operator_compare for the instance foo would be called with the rhs parameter as NIL.

You can try this for yourself very quickly.

Create a new desktop project. In that new project add a Class named myClass. Add a method to myClass, Public operator_compare(rhs as myClass) as Integer

Simply put a break statement in the code

Now in Window1.open put

dim foo as new myClass

if foo = nil then // you will hit your break statement in the class
end if

if foo is nil then // you will NOT hit the break statement in the class
end if

The advice here is to be REALLY careful about when you use IS or =, or other comparison operators like >= <= <> etc, as they could mean VERY different things. And without reviewing code you can’t be sure whether a class does or does not have operator_compare implemented.

Use IS when you mean “are these the referring to the same instance”

Use the others when you _may_ mean something else.

Decide by not deciding

I was doing some reading on the weekend and came across some really good thoughts on how to make decisions in code – but not by using conventional if or select branching mechanisms or others that masquerade as flow control statements under other guises.

There’s a whole movement for “if-less programming”.

And it fits very well with using OOP and the capabilities of polymorphism in ways that make your code clearer and easier to maintain and extend.

Let’s say you have a class that represents vehicles. Your program permits you to have many types of vehicles with various capabilities. And somewhere in that class that represents a vehicle you might have code like :

Function calculateMaximumWeightCapacity() as Double
  if ( vehicleType = "Transport" ) then
     // we have to account for the fact this has 18 wheels and 5 axles
  elseif ( vehicleType = "Truck" ) then
     // we have to account for what kind of light duty truck this is
  elseif ( vehicleType = "Car" ) then
     // we have to account for what kind of car this is as a mini cant
     // carry as much as a impala
  end if
End Function

Yes this is contrived but you get the point

IF you have classes that display this kind of code then you probably should consider using polymorphism in a way it can make you life easier.

In your application, if you have this kind of code, then EVERY time you want to add a new kind of vehicle you have code to adjust. You’ll need to update every possible place this kind of selection goes on. And if you miss one you have bugs.

If However we used polymorphism to help us we could be sure that any time we added a new vehicle type we definitely covered all the required functionality AND that we didnt have to adjust a lot of code in many places.(1)

Instead if we had

Class Vehicle
    Private Sub Constructor()
      // this is so we make this class "abstract" and 
      // you cannot create new vehicles - you MUST create 
      // instances of subclasses only
    End Sub

    Function calculateMaximumWeightCapacity() as Double
      // since we have NO way to FORCE a subclass to override this 
      // we put a break in here so we can figure out which subclass 
      // did NOT override this
      BREAK
    End Function
End Class

Class Transport
  Inherits Vehicle
    Function calculateMaximumWeightCapacity() as Double
        // we have to account for the fact this has 18 wheels and 5 axles
        return 30000 // just for fun !
     End Function
End Class

Class Car
  Inherits Vehicle    
End Class

Class Mini
  Inherits Car
    Function calculateMaximumWeightCapacity() as Double
      // we have to account for what kind of car this is as a mini cant
      // carry as much as a impala
      return 500
     End Function
End Class

Class Impala
  Inherits Car
    Function calculateMaximumWeightCapacity() as Double
      // we have to account for what kind of car this is as a mini cant
      // carry as much as a impala
      return 1000
     End Function
End Class

.. and so on ...

And this gets rid of the need to use an IF to test what kind of vehicle it is to determine how to compute the weight. The specific subclass just does it knowing that its a transport, a truck, a mini or an impala.

Function calculateMaximumWeightCapacity() as Double
  return self.calculateMaximumWeightCapacity()
End Function

Note that this code is much simpler to follow.

And when you need to add a new kind of vehicle you add a new class type, recompile and off your program goes because you havent had to hunt around and find all the places where you need to check vehicle types and maybe introduce new bugs.

Polymorphism is definitely your friend here.

footnotes

(1) there are some things that Xojo does NOT provide that would make life simpler. A means of forcing a subclass to override a specific method defined in a super class does NOT exist. IF we use a base class we can only catch that a subclass has not overridden a method. Some languages have a means for a base class to define a method that subclasses MUST implement. Xojo does not.

Its possible to use an interface to force implementors of an interface to implement a method BUT this MAY be the wrong approach for the specific problem.