Thursday 8 May 2008

Telling the truth

We all know that REAL Software can't be bothered to document REALbasic properly, so it comes as no surprise that I can find no reference in the docs to the pairs class, the only new feature RS is advertising for 2008r2.

Of course, Aaron has stepped in and documented this on his blog so it's no great hardship for me personally, as I check his blog most days.

What does come as a bit more of a surprise is that, even now, the RS website is claiming

Windows: Unlike most other Windows development tools, REALbasic generates self-contained executables which are not dependent on external dlls or pre-installed frameworks. The single .exe file produced by the REALbasic compiler is all you need to distribute to you customers.
This has been mentioned on the forums, I've PM'd members of RS staff about it hours ago, I've cleared every browser cache in sight and connected via different ISPs. It's still there.

Does the U.S.A. have no laws about false advertising? In a litigious society like the U.S. are people actually putting up with this sort of thing?

The single executable is a central claim about the way that RB can be deployed and should have been removed from the website as soon as RS realised they might be going to change it.

Of course there will be changes to how RB works over time but anyone who has bought or renewed RB recently could be forgiven for feeling they have been badly misled.

It's a real shame because 2008r2 seems to be a really nice release. Why doe RB's documentation and advertising so often end up wrecking the positive feel we would otherwise get?

Tuesday 22 April 2008

Feedback changes

I probably should not write this first paragraph publicly. The beta list has been awash lately with phrases like, "I really like this new spirit of openness," "thanks for keeping us informed" and even "thanks for listening, the changes are much better than your original proposal."

And then comes the announcement that the current feedback system is being replaced and will no longer be searchable. We can no longer see other people's reports.

Within seconds, I hit the bookmark to my watchlist, so I could pdf my outstanding reports.
But they had already gone.

That's what really irritates me. The sudden withdrawal of the data I keep around to remind me of workarounds to bugs I or others have already found.

If RS need a better project management system, it hardly comes as a surprise.

If they want to use its built-in bug-tracking, I hope and expect it will work better for them.

If they have decided to use a hosted system rather than host their own copy, who am I to argue.

And if they don't want to waste resources creating non-standard versions of FogBugz, nobody will suggest they look like a company with engineers to spare.

Other people complain that thousands of customers are being asked to waste their time to save a bit of centralized time at RS. This may be true but it may well be worthwhile.

It's the lack of notice that leads to the conspiracy theories.

What could be a possible motive for withdrawing the old data?

  • RS don't want the world at large to be able to see how many bugs they have?

What could be a possible motive for giving no notice?
  • To make it more difficult for some third-party to compile a website (wiki?) listing outstanding bugs?

It may well be that neither of these is the case.

It may well be that RS's normal policy of secrecy has engendered an attitude where, when considering a change, nobody even thinks to ask until the last minute, "How should we communicate with our customers to cause least upset?"

Personally, I really hope FogBugz works well for RS and I'll live with whatever decisions they make about customer access.

If I find a bug that doesn't affect me personally, it's quite likely I will assume somebody else has reported it.

If somebody else posts a bug to a mailing list or forum that does affect me, it's quite likely I will assume they may not have reported it and will paste a copy of it (altered as required to fit my personal prejudices) straight into the feedback system.

I'm sure somebody else will provide hosting for a public bug-list out of RS's control.
If so, I will do my best to contribute.

And just for the record, my business doesn't rely on RB at all.

So if I see RS getting heavy-handed with anyone that tries to maintain a public bug-list, I will just decide that RS is not a company with whom I need a business relationship any more.

It's a real shame I am even beginning to feel that way. My goodwill towards RS has been sky-high lately because stuff seemed to be moving in the right direction.

If I had had a few days notice that my watchlist was going to disappear, I would be slightly irritated but would now be posting "give it a while to see how it works" messages in reply to the current storm of complaints.

Wednesday 2 April 2008

Yuma

I've been playing with Yuma and it's great fun.

I've got a lot of learning to do but I thought I'd mention one or two bits I've found useful.

I have an include file called myGlobals.yuma which includes methods



Sub MsgBox(s As String)
Function MsgBox(s As String, buttons as Integer) As Integer
Function MsgBox(s As String, buttons as Integer, Title As String) As Integer
Sub printLine(s As String)
Sub printParagraph(s As String)
Function lineBreak() As String
Const TargetYuma = True
The msgBoxes are just to stop test code falling over when I compile for RB and Yuma.

The other methods are for simpler formatting within Yuma and try to make the source a bit more readable when adding breaks or paragraphs to the output.

TargetYuma helps with conditional compilation.

In my RB code, I use a similar module which stops the RB code from falling over by having methods
Sub print
Sub PrintLine(s As String)
Sub printParagraph(s As String)
Function lineBreak() As String
Const TargetYuma = False
I save the project in VCF format, so picking classes and modules and converting them to Yuma then becomes a breeze.

Some of the very simple stuff I've tried so far is available for download from my website but please be aware that site is not running Yuma. The .yuma files need to be downloaded and tested on your own yuma development server.

Sunday 23 March 2008

Self and Me

A question that comes up a lot in REALbasic is

What is the difference between the Self and Me keywords?
Everybody eventually thinks they have it sorted out in their own minds but it's surprising how many of us then find we're wrong.

I think that essentially it goes something like this:
Self and Me always refer to the same thing, except in the specific instance where you are editing the method handlers of a class in a Window. In those circumstances, Self refers to the item you're editing (the window) and Me refers to the class instance which exposes the method.
The best advice I ever received on this was (I think) from Mars.

If you want to know what Self refers to, while you're coding, look up at the top of the IDE.

If the title bar says
Realbasic - [Untitled] - Class1
then Self refers to Class1. On the other hand, if the title bar says
Realbasic - [Untitled] - Window1
then Self refers to Window1

Sunday 16 March 2008

Threads - Cooperative and Preemptive

Lots of developers talk about multiple processors in the same dubious
way they've always spoken of bigger screens and higher screen resolutions.

If the user happens to have more, how can I fill it up?
All those resources aren't there so the computer can always run one app more greedily. In general, they're about allowing a richer multi-tasking experience.

I admit that a few apps will benefit from more processing power than one processor can provide but it's not a good idea to rely on high-end CPUs for most programs in any language.

REALbasic "threads" are not preemptive thread such as programmers coming from other environments might expect, they are cooperative threads which some people are surprised to learn are still exposed by the various operating systems.

We'll ignore the argument that what Microsoft call "fibres" (I can't bring myself to use MS spelling) might not really be entitled to the name "thread" on Windows any more.

There are ways (MBS is one but not the only) of attempting to use preemptive threads with RB but RS engineers assure us there is no safe way to use the framework with preemptive threads that does not effectively cripple them back to cooperative.

I don't try to use preemptive threads in RB because I believe it may eventually give crashes or (possibly worse) unpredictable results.
(This is a very slightly stronger statement than I make about using App.DoEvents in a gui app. I might try that in one particular set of circumstances.)

Sometimes to get around the lack of preemptive threads and still keep the gui responsive, I have to split long external reads up into shorter chunks. This can sometimes be a pain, especially with databases.

Sometimes I have to split out lengthy tasks into a helper app. If that is also a RB app, it significantly increases the size of my app's footprint on the disk.

I'd love to see preemptive threads in RB but my guess is
  1. we won't see them for a long time
  2. they'll take an even longer time to settle down when they do arrive
  3. they won't really make much difference to me
And of course there are many fixes and lots of new features (and their fixes) I'd like to see first.

Friday 14 March 2008

Personal Messages on the Forums

I've been trying to be helpful on the forums for a while now and in general people seem to appreciate most of my efforts.

One thing that does happen quite a lot is that I post a reply to a query, then the original poster (or someone else) wants to start a follow-up discussion by personal message.

Usually I respond to this by giving a general reply to any follow-up questions, followed by a note something like

I prefer not to give too much advice by PM. If I'm going to try to be helpful, I like as many people as possible to benefit from it.

If you have any further questions, it works better if you ask them publicly and I (or someone else) respond on the forums.
Most people take the hint. Some apologise (for which there is no need at all) and some never speak to me again (or that's the way it seems to me)

Some people, however, just ignore the note and ask the next question in another PM.

I may give them the benefit of the doubt once and assume that our messages crossed, while the poster was composing his question.

I may reopen the correspondence myself by suddenly remembering something else I didn't put in my original reply. Then it's only reasonable to accept a couple more PMs before giving up.

To a subsequent question, if I'm feeling reasonably polite, I may reply
We really should discuss this publicly in the forum.
But after that, I really can't think of anything polite to write, except to tell them exactly what I charge for consultancy. I normally express this in USD per hour, even though my charges are nearly always in GBP.

Strangely enough, that usually ends the conversation.

Thursday 13 March 2008

Names for colours

I needed to display names for lots of colours the other day and ended up with an Extends function to return x11 names.

It occurred to me it might be useful to someone else.

To use it, just create it as a method in a module. It does have to be in a module.

Then you can use it like this

dim c as Color = &cCD5C5C
MsgBox c.x11name

There is a demo project at http://rb.sgarman.net/x11colours.rbp which is just a small test harness I threw together for this function and its reverse.

Anyway, here's the method

Function
X11name(Extends c As Color, allowBlanks As Boolean = true) As String
Static Dict as Dictionary
if dict is nil then
dict = new Dictionary
Dict.Value( &c000000 ) = "Black"
Dict.Value( &c000080 ) = "Navy"
Dict.Value( &c00008B ) = "DarkBlue"
Dict.Value( &c0000CD ) = "MediumBlue"
Dict.Value( &c0000FF ) = "Blue"
Dict.Value( &c006400 ) = "DarkGreen"
Dict.Value( &c008000 ) = "Green"
Dict.Value( &c008080 ) = "Teal"
Dict.Value( &c008B8B ) = "DarkCyan"
Dict.Value( &c00BFFF ) = "DeepSkyBlue"
Dict.Value( &c00CED1 ) = "DarkTurquoise"
Dict.Value( &c00FA9A ) = "MediumSpringGreen"
Dict.Value( &c00FF00 ) = "Lime"
Dict.Value( &c00FF7F ) = "SpringGreen"
Dict.Value( &c00FFFF ) = "Aqua"
Dict.Value( &c00FFFF ) = "Cyan"
Dict.Value( &c191970 ) = "MidnightBlue"
Dict.Value( &c1E90FF ) = "DodgerBlue"
Dict.Value( &c20B2AA ) = "LightSeaGreen"
Dict.Value( &c228B22 ) = "ForestGreen"
Dict.Value( &c2E8B57 ) = "SeaGreen"
Dict.Value( &c2F4F4F ) = "DarkSlateGray"
Dict.Value( &c32CD32 ) = "LimeGreen"
Dict.Value( &c3CB371 ) = "MediumSeaGreen"
Dict.Value( &c40E0D0 ) = "Turquoise"
Dict.Value( &c4169E1 ) = "RoyalBlue"
Dict.Value( &c4682B4 ) = "SteelBlue"
Dict.Value( &c483D8B ) = "DarkSlateBlue"
Dict.Value( &c48D1CC ) = "MediumTurquoise"
Dict.Value( &c4B0082 ) = "Indigo"
Dict.Value( &c556B2F ) = "DarkOliveGreen"
Dict.Value( &c5F9EA0 ) = "CadetBlue"
Dict.Value( &c6495ED ) = "CornflowerBlue"
Dict.Value( &c66CDAA ) = "MediumAquamarine"
Dict.Value( &c696969 ) = "DimGray"
Dict.Value( &c6A5ACD ) = "SlateBlue"
Dict.Value( &c6B8E23 ) = "OliveDrab"
Dict.Value( &c708090 ) = "SlateGray"
Dict.Value( &c778899 ) = "LightSlateGray"
Dict.Value( &c7B68EE ) = "MediumSlateBlue"
Dict.Value( &c7CFC00 ) = "LawnGreen"
Dict.Value( &c7FFF00 ) = "Chartreuse"
Dict.Value( &c7FFFD4 ) = "Aquamarine"
Dict.Value( &c800000 ) = "Maroon"
Dict.Value( &c800080 ) = "Purple"
Dict.Value( &c808000 ) = "Olive"
Dict.Value( &c808080 ) = "Gray"
Dict.Value( &c87CEEB ) = "SkyBlue"
Dict.Value( &c87CEFA ) = "LightSkyBlue"
Dict.Value( &c8A2BE2 ) = "BlueViolet"
Dict.Value( &c8B0000 ) = "DarkRed"
Dict.Value( &c8B008B ) = "DarkMagenta"
Dict.Value( &c8B4513 ) = "SaddleBrown"
Dict.Value( &c8FBC8F ) = "DarkSeaGreen"
Dict.Value( &c90EE90 ) = "LightGreen"
Dict.Value( &c9370DB ) = "MediumPurple"
Dict.Value( &c9400D3 ) = "DarkViolet"
Dict.Value( &c98FB98 ) = "PaleGreen"
Dict.Value( &c9932CC ) = "DarkOrchid"
Dict.Value( &c9ACD32 ) = "YellowGreen"
Dict.Value( &cA0522D ) = "Sienna"
Dict.Value( &cA52A2A ) = "Brown"
Dict.Value( &cA9A9A9 ) = "DarkGray"
Dict.Value( &cADD8E6 ) = "LightBlue"
Dict.Value( &cADFF2F ) = "GreenYellow"
Dict.Value( &cAFEEEE ) = "PaleTurquoise"
Dict.Value( &cB0C4DE ) = "LightSteelBlue"
Dict.Value( &cB0E0E6 ) = "PowderBlue"
Dict.Value( &cB22222 ) = "FireBrick"
Dict.Value( &cB8860B ) = "DarkGoldenrod"
Dict.Value( &cBA55D3 ) = "MediumOrchid"
Dict.Value( &cBC8F8F ) = "RosyBrown"
Dict.Value( &cBDB76B ) = "DarkKhaki"
Dict.Value( &cC0C0C0 ) = "Silver"
Dict.Value( &cC71585 ) = "MediumVioletRed"
Dict.Value( &cCD5C5C ) = "IndianRed"
Dict.Value( &cCD853F ) = "Peru"
Dict.Value( &cD2691E ) = "Chocolate"
Dict.Value( &cD2B48C ) = "Tan"
Dict.Value( &cD3D3D3 ) = "LightGrey"
Dict.Value( &cD8BFD8 ) = "Thistle"
Dict.Value( &cDA70D6 ) = "Orchid"
Dict.Value( &cDAA520 ) = "Goldenrod"
Dict.Value( &cDB7093 ) = "PaleVioletRed"
Dict.Value( &cDC143C ) = "Crimson"
Dict.Value( &cDCDCDC ) = "Gainsboro"
Dict.Value( &cDDA0DD ) = "Plum"
Dict.Value( &cDEB887 ) = "BurlyWood"
Dict.Value( &cE0FFFF ) = "LightCyan"
Dict.Value( &cE6E6FA ) = "Lavender"
Dict.Value( &cE9967A ) = "DarkSalmon"
Dict.Value( &cEE82EE ) = "Violet"
Dict.Value( &cEEE8AA ) = "PaleGoldenrod"
Dict.Value( &cF08080 ) = "LightCoral"
Dict.Value( &cF0E68C ) = "Khaki"
Dict.Value( &cF0F8FF ) = "AliceBlue"
Dict.Value( &cF0FFF0 ) = "Honeydew"
Dict.Value( &cF0FFFF ) = "Azure"
Dict.Value( &cF4A460 ) = "SandyBrown"
Dict.Value( &cF5DEB3 ) = "Wheat"
Dict.Value( &cF5F5DC ) = "Beige"
Dict.Value( &cF5F5F5 ) = "WhiteSmoke"
Dict.Value( &cF5FFFA ) = "MintCream"
Dict.Value( &cF8F8FF ) = "GhostWhite"
Dict.Value( &cFA8072 ) = "Salmon"
Dict.Value( &cFAEBD7 ) = "AntiqueWhite"
Dict.Value( &cFAF0E6 ) = "Linen"
Dict.Value( &cFAFAD2 ) = "LightGoldenrodYellow"
Dict.Value( &cFDF5E6 ) = "OldLace"
Dict.Value( &cFF0000 ) = "Red"
Dict.Value( &cFF00FF ) = "Magenta"
Dict.Value( &cFF00FF ) = "Fuchsia"
Dict.Value( &cFF1493 ) = "DeepPink"
Dict.Value( &cFF4500 ) = "OrangeRed"
Dict.Value( &cFF6347 ) = "Tomato"
Dict.Value( &cFF69B4 ) = "HotPink"
Dict.Value( &cFF7F50 ) = "Coral"
Dict.Value( &cFF8C00 ) = "DarkOrange"
Dict.Value( &cFFA07A ) = "LightSalmon"
Dict.Value( &cFFA07A ) = "LightSalmon"
Dict.Value( &cFFA500 ) = "Orange"
Dict.Value( &cFFB6C1 ) = "LightPink"
Dict.Value( &cFFC0CB ) = "Pink"
Dict.Value( &cFFD700 ) = "Gold"
Dict.Value( &cFFDAB9 ) = "PeachPuff"
Dict.Value( &cFFDEAD ) = "NavajoWhite"
Dict.Value( &cFFE4B5 ) = "Moccasin"
Dict.Value( &cFFE4C4 ) = "Bisque"
Dict.Value( &cFFE4E1 ) = "MistyRose"
Dict.Value( &cFFEBCD ) = "BlanchedAlmond"
Dict.Value( &cFFEFD5 ) = "PapayaWhip"
Dict.Value( &cFFF0F5 ) = "LavenderBlush"
Dict.Value( &cFFF5EE ) = "Seashell"
Dict.Value( &cFFF8DC ) = "Cornsilk"
Dict.Value( &cFFFACD ) = "LemonChiffon"
Dict.Value( &cFFFAF0 ) = "FloralWhite"
Dict.Value( &cFFFAFA ) = "Snow"
Dict.Value( &cFFFF00 ) = "Yellow"
Dict.Value( &cFFFFE0 ) = "LightYellow"
Dict.Value( &cFFFFF0 ) = "Ivory"
Dict.Value( &cFFFFFF ) = "White"
end if
Dim retval as String
retval = dict.Lookup( c, "" )
If retval = "" and allowBlanks = false then
dim v as Variant
v = c
retval = mid( v.StringValue, 3 )
End If
Return retval
End Function

Saturday 23 February 2008

How do I feel about RB?

I'm really confused about how I feel about REALbasic.

I like the engineers. Aaron, Mars, Mike and William are my friends. This is in much the same way that the soap stars are my cousin's friends.

I like the build engineer, Nathan. And who could fail to like Marco.

But I don't like the company much. Its public utterances, though mostly truthful, are often misleading and the company is far too secretive for my liking. I do not mean the utterances by my friends (see above) are misleading.

I like what REALbasic wants to be. I quite like a lot of what it is. But it is the most buggy development environment with which I work by a long way.

It has far too many features which have been included to add to the feature list and have never worked properly or have been left in an unreasonably basic state. Far too many bugs are fixed (or half fixed) and then come back later without anyone seeming to notice.
If your testing doesn't pick up recurrences of old bugs, what can you hope it will pick up?

Now because criticism of the product implies criticism of my friends, I become very defensive when the number one whiner starts again.

But then people tell him he should cut RS some slack because my friends are the only engineers. And then I get really irritable because the company refused to tell me how many engineers there are, even when I offered to sign a non-disclosure agreement and so my best customer won't let me write any of his stuff in RB.

So I join in with the whining. Then I feel guilty because I'm criticising the product that should be so wonderful because it has the right aspirations and is pretty good just as it is now.

So for now I just keep swapping sides and therefore disagreeing with nearly every post I see about the quality, usefulness and future of REALbasic

But for all that, most of the programming I do for myself or for fun I do in REALbasic and will continue to do so.

Tuesday 15 January 2008

Another new feature

So, rb2008 will introduce introspection.

Geoff claims it's for the customers' benefit and there will be much screaming from the gallery that RS should be spending their time fixing bugs instead of adding features.

Of course they're concentrating mostly on bug-fixes but some people believe the new features are marketing-led.

What I ask myself is this. Are they spending time adding the features they feel they need to enable them to fix the bugs?

They've been eating their own dogfood for a while now and may be realising there's stuff it ain't so easy to do in RB and they need a few more features to do some of the things they need to do next.

Remember, writing a toolset exposes you to the unpredictable foibles of other developers, just about as badly as anything I can think of.

If you were building a toolset, might you not find you'd give your eye teeth for features like:

  • Introspection
  • Delegates
  • Control scope
  • destination directory and command line arguments for debug applications
  • plugin debuggin'
  • turning off implicit instantiation
  • namespaces
Is it just me, or are their stomachs just revolting against the lack of meat in the dogfood?