[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