[Gambas-user] a few suggestions for improvement

Toni Schornboeck lists at ...706...
Wed Jan 5 15:24:18 CET 2005


Hello Folks. 

First I want to say that I like the Gambas Environment very much.
But there are a few things that I don't like.
I want to explain what I don't like, why and how it could be improved.
I would be glad if you could answer me and discuss my proposals. 


After a Form is closed, the object still lives, but at the same time is 
dead.
I'd like to write code like:
dim f as Form
f=new Form(foo)
f.ShowModal()
return f.Result 

or something like that. But it is not possible, because f dies after 
"ShowModal()"
I think that is unecessary. f should stay alive until it gets out of scope.
It would be OK, if a closed form can never be opened again, therefore a
f.ShowModal()
f.ShowModal()
could raise an error. 

Take for example a InputBox. AFAIK the currently best solution is:
static public function Run() as String
 dim f as InputBox
 f=new InputBox
 f.ShowModal()
 return value
end 

private static value as String 

public sub Form_Close()
 value=Text1.Text
end 

This Solution is just Plain ugly and can lead to Bugs, when 2 InputBoxes are 
open at the same time. 

 

A constructor has always to be public. Why?
I'd like to declare a constructor private to force the user of my code to 
use a static
construct (that means: a static function that returns the object).
This can sometimes be useful, for example when using a factory to prohibit 
the user from directly instanciating
objects. 


This leads to another point: friends could be useful or something like Java 
Packages where one can declare a method
as package private. 


optional parameters are very useful, but why can I only assign a default 
value to primitive types?
private sub foo(optional i as integer = -1)
is perfectly legal, but
private sub foo(optional o as Bar=new Bar(baz))
is rejected :(
It would be nice to define default values also for objects. 

The workaround using
if isnull(o) then o=new Bar(baz)
doesn't always work.
Because NULL may be a perfectly legal value in some cases. 

 

for each on collections acts weird.
for each v in col
 print col.Key & "=" & v
next
This looks ugly. col is changed even though I don't write to it, but just 
read values from it.
And it isn't really intuitive to look for key in col... 

It would be nice if we could introduce an iterator concept.
But this is quite controversal, so I would like to get your opinion first, 
before thinking
too far. 

 

I really miss a 'super' or 'base' keyword to access the Baseclass from 
within the derived class.
In my current work I have this Code:
PUBLIC FUNCTION doGetQuery() AS SelectQuery
 DIM query AS SelectQuery
 DIM super AS DependentDataSource 

 IF IsNull($con.Value()) THEN RETURN NULL 

 super=ME
 query=super.doGetQuery()
 query.AddWhere($field & "='" & CStr($con.Value()) & "'") 

 RETURN query
END 

DependentDataSource is the Baseclass.
I have to do an upcast (without casting operators, I'll talk about them a 
bit later) to access
doGetQuery() of the base class.
It would be much nicer if I could simply write
SUPER.doGetQuery() 

 

This leads to another point:
Why can't I define which parameter are passed to my base class?
Take for example a XML Parser. There are a few Node classes, all derived 
from BaseNode.
Every Node contains an array of allowed child nodes.
One could write:
SomeNode.class:
public sub _new()
 'call base constructor
 super(allowedChildren)
end 

but currently this isn't possible because the user has to specify the 
params.
but in this code only the class itself knows which child nodes are allowed 
and the user
shouldn't care. 

The workaround using set-Methods to set the allowed children afterwards is 
not perfect, because
the child nodes should be set exactly once when the object is instaciated 
and shouldn't change
later. 

 

I already mentioned the lack of casting Operators.
Take for example another code from my current work (stripped down):
 DIM control AS Control

 SELECT CASE type
   CASE "select"
     control=NEW ComboBox(detailFrame) AS "EditControls"
     Object.SetProperty(control, "ReadOnly", TRUE)
 END SELECT 

this factory creates a control depending upon a parameter.
It has to set a few parameters, like ReadOnly=TRUE
It would be nice if I could write:
((ComboBox)control).ReadOnly=TRUE
or
Cast(ComboBox, control).ReadOnly = TRUE
or something like that. 

If I could declare variables everywhere I like would also help. 


This leads to: variables must be declared at begin of function
why is that? 

In C it was a pain in the ass, so they removed this restriction with C99 and 
no other major language hast
that restriction. Even VB doesn't ;) 

It would be really important to allow the user to declare variables as local 
as possible.
it is even more important because gambas functions tend to be bigger than 
for example Java or C++ functions
(my own personal expierence) 

 

A very controversal point is:
no RETURN will return NULL
I'd prefer a warning when I forgot to write a return statement within a 
function. 

 

One thing that really annoys me is:
arr.Add(new Foo(bar))
doesn't work. 

I have to write
dim t as Foo 

t=new Foo(bar)
arr.Add(t) 

I worked around it by providing a static public make function:
static public make(p as Bar)
 dim obj as Foo
 obj = new Foo(p)
 return obj
end
so I can write
arr.Add(Foo.make(bar)) 

but it would be nice if I could simply write new Foo everywhere where I can 
put a Foo object. 

 

another nice feature would be, if one could declare a variable inside a for 
statement: 

for i as integer = 0 to 10 

i would be accessably only within the for loop
this would be very convenient. it would also help to hold variables as local 
as possible.
one normally uses a loop variable i just for looping and nothing more so it 
would be really nice if one
could express the use of i this strong and obvious. 

 

Why doesn't gambas do virtual dispatching?
I have a base class called Base and a derived class called Derived.
bot implement the method GetQuery() 

When I have a reference to Base (which really is a reference to Derived, but 
was upcast)
and call GetQuery() it will call Base's GetQuery instead of Derived's one. 

I have to use
Object.Call(obj, "GetQuery")
but this isn't so nice. 

So I worked around it by implementing GetQuery only in Base which looks 
like:
public function GetQuery() as Foo
 return Object.Call(ME, "doGetQuery")
end 

Derived and Base implement also doGetQuery which does the actual work.
But the drawback is: doGetQuery can't be private, because Object.Call 
wouldn't have access to it... 

I would like to see virtual dispatching in gambas improved, because 
currently it is (IMHO) a mess. 

 

The next issues are about the IDE gambas:
I'd love to see the possibility to set the Tabstop ordering.
currently I have to edit the *.form files and reorder the components. that 
could be improved! 

 

It would improve the usability of the IDE if I could create directories to 
store my class and form files
currently I have about 30 *.call files. conceptional there are 3 modules. if 
i could store them in 3 directories
it would improve the management of them a lot. 


a minor issue: the executale file of my project contains a lot of 
information that shouldn't be there
for example: 

Project=ReportGenerator
Title=ReportGenerator
Startup=Report
TabSize=2
Argument=-h localhost -l schorny -p <snip> -n akademie
Version=0.0.16
Library=gb.db
Library=gb.xml.libxml
SnapToGrid=1
ShowGrid=1
Snap=8
Localize=0
KeepDebugInfo=0
ControlPublic=0
ExecPath=/home/schorny/code/ReportGenerator/report
Prefix=0 

I think most of them are unecessary. And "Argument" is a bit dangerous - it 
contains the params that the IDE should use when
calling the program. as you can see: it contains the login information for 
my test db. I don't want to give them to every user ;) 

 

even though if have postet a lot of critic: I like gambas.
Otherwise I wouldn't have convinced my boss to use Gambas for our Linux 
Clients ;) 

currently the best RAD environment for Linux/KDE -> congratulations!




More information about the User mailing list