[Gambas-user] Re: a few suggestions for improvement

Benoit Minisini gambas at ...1...
Wed Jan 12 14:03:29 CET 2005


On Friday 07 January 2005 10:24, Toni Schornboeck wrote:
> Benoit Minisini writes:
> >> After a Form is closed, the object still lives, but at the same time is
> >> dead.
> >> Well, I dont find that ugly, and if you have several instances of your
> >> form,
> >
> > just don't declare the variable static.
>
> It was my bad. Thanks to Oliver Stieber for providing this workaround
> without
> a static variable.
>
> But there is another problem with dieing forms:
> For example in .NET a Dialog has also a Property which indicates which
> button
> was pressed to close the form.
>
> The thing I want to achieve is 'easier' coding:
>
> dim f as Form
> f=new Form(bar)
> f.ShowModal()
> if f.Closed = Form.Cancel then return
> handle_value(f.Value)
>
> would be very nice :) The 'Problem' with Oliver's workaround is: If I
> return an object, I can return NULL to say "user pressed cancel" but if I
> want to return
> a primitive type like int or so, that is not possible. And 3 states (for
> example:
> Ignore, Retry, Cancel) wouldn't work.
>
> Of course, one can workaround this - but more than one return value by
> function
> would add complexity that wouldn't be necessary.
>
> And I personally don't like it, when an object dies without me calling
> Close(), a
> destructor, finalize() or any other explicit killing method.
>
> I think the code is not intuitive when an object dies because I called
> Show() on it...
>
> But the workaround from Oliver is a good solution.
>
> >> A constructor has always to be public. Why?
> >
> >It is by design.
>
> Could you consider changing this or adding an other method for prohibiting
> client code
> to instanciate an object?
> When writing a complex class hierachies i find it sometimes necessary to
> force the user to
> use a factory instead of instanciating object by himself.
>
> >> 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.
> >
> >At the moment, I don't see any mean to do that cleanly.
>
> For example:
> A XML Parser which holds concrete Nodes:
> All are subclasses of NodeBase
>
> The Parser doesn't care about the different Nodes, it just calls
> parentNode.AddChild(CreateNodeFromTag(tag))
>
> it wouldn't make any sense to create a specific Node. So
> CreateNodeFromTag() creates a
> Node from the Tag and takes into account that some Tags produce the same
> Node class and so on.
>
> The idea behind this is: client code need not to have any clue about the
> different node classes,
> they just don't show. All is hidden behind NodeBase. For the client code it
> doesn't matter if
> the tag "<foo>" creates a FooNode or BarNode, it just calls node.Process()
> and the node does its job :)
>
> Of course it works without defining private constructors, but it could help
> to keep the user from
> doing odd things he is not supposed to do.
>
> >> This leads to another point: friends could be useful or something like
> >> Java Packages where one can declare a method
> >> as package private.
> >
> >In Gambas, public means exported. If something is private in a class, then
> > the interpreter can't access it from outside the class. So, constructors,
> > destructors, event handlers... need to be public, or the interpreter
> > won't be able to call them.
>
> I understand.
>
> But for further versions, would it be possible to consider a package system
> like Java's?
> The idea is:
> exporting not all classes and methods.
> That could be usefull when writing libraries in gambas.
>
> The Java Collections show us, how nice this can be when not everything is
> visible for the client.
>
> And of course there are often internal helper classes. These should be also
> kept private and hidden :)
> So we can keep the public interface of a library very slim and clean.
>
> >> optional parameters are very useful, but why can I only assign a default
> >> value to primitive types?
> >
> >I think it is just something to change in the compiler. So it may be
> >possible :-)
>
> That would be very helpful and would add clarity to code.
> Because I think one of the important things about a language is
> consistency. There shouldn't be unecessary differences between primitive
> types and 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.
> >
> >Well, in your example, NEW will never return NULL.
>
> Yes, this would be just a workaround:
>
> public sub foo(o as Bar)
>  if isnull(o) then o=new Bar(baz)
>
> instead of
> public sub foo(o as Bar = new Bar(baz))
>
> but the difference is:
> foo(null)
> will yield different results, because my first version would assume that no
> value was provided
> and override null with new Bar(baz) but maybe null would be a correct value
> and not the default one ->
> this would be impossible to implement.
>
> >> for each on collections acts weird.
> >
> >I don't unserstand what you say. Collection.Key is just a read-only
> > property that returns the key of the last entry accessed in the
> > collection. I don't see where the collection is modified during the
> > iteration...
>
> I'm sorry, I haven't explained enough because I thought my point would be
> obvious (which was stupid of me
> because if it is obvious and clear to you, you wouldn't have implemented in
> that way ;))
>
> So here is a better explaination:
>
> The problem as I see it are some very hard to find bugs:
>
> for each v in col
>  if ShallEntriesBeDeleted(col.Key) then
>    DeleteAllEntriesLike(col, col.Key)
>  end if
>  LogMessage("All Entries Like " & col.Key & " have been deleted")
> next
>
> See the bug?
> col.Key in
> DeleteAllEntriesLike(col, col.Key)
> and in
> LogMessage("All Entries Like " & col.Key & " have been deleted")
> are 2 different values.
> And to add obscurity: the value of col.Key in
> LogMessage("All Entries Like " & col.Key & " have been deleted")
> deepends on the implementation of DeleteAllEntriesLike
>
> The problem is:
> col.Key can change everytime I pass col to an extern function. I can't know
> if it will change or not, but it can change.
>
> So I have to store col.Key in a separate variable.
> Now the reader of my code has to figure out, if I'm using col.Key or a
> separate variable.
> This add complexity.
>
> >> I really miss a 'super' or 'base' keyword to access the Baseclass from
> >> within the derived class.
> >
> > You are right, SUPER is missing. It's in my TODO list.
>
> Thank you.
>
> >> Why can't I define which parameter are passed to my base class?
> >
> > Try that:
> >
> > BaseNode.class:
> >
> > PUBLIC SUB _new()
> > ...
> > END
> >
> > SomeNode.class:
> >
> > PUBLIC SUB _new(allowedChildren)
> > ...
> > END
> >
> > Each class in the inheritance hierarchy consumes the parameters passed to
> > the constructor.
>
> Yes, and so I have to implement a SetAllowedChildren() function, or do I
> miss an important
> point?
>
> BaseNode holds all allowedChildren but it doesn't know what they are.
> SomeNode has to set
> all allowedChildren when it is created. currently SomeNode can't pass any
> parameter to BaseNode's
> constructor. SomeNode has to use a SetAllowedChildren() function, which
> allowes to change the nodes
> during runtime, which shouldn't be allowed.
> OK, one can introduce a sealed flag, which can be set once and afterwards
> never changed to indicate if
> SetAllowedChildren() will succeed.
>
> >> I already mentioned the lack of casting Operators.
> >
> > If I remember, you can do ComboBox(...) to cast to ComboBox. Test it to
> > see if it really works.
>
> Oh, I'm sorry. It works perfectly.
> I must have overlooked it in the documentation, sorry.
>
> >> This leads to: variables must be declared at begin of function
> >> why is that?
> >
> > I find declaring variable everywhere a source of confusion and unreadable
> > code. So I force them to be declared at the beginning of the function.
> > And one by line at the moment ?
>
> One by line is good practice, but only at begin of scope?
> But I see, we can argue as much as we like, but neither of us will change
> his mind about
> that, right?
>
> FOR??
>
> >> It would be really important to allow the user to declare variables as
> >> local as possible.
> >
> > You are not compelled to write large functions...
>
> I know, and 90% of the functions in my current work are less than 10 lines
> of code.
> But there are a few functions that just initialize something.
> They take more than 10 lines, but I think it is OK, because it is very easy
> to understand
> the meaning (they just initialize the components on the form)
>
> And sometimes there are a few variables that are only needed at the end of
> the function...
> OK, I'll stop arguing ;)
>
> >> A very controversal point is:
> >> no RETURN will return NULL
> >
> > It is by design.
>
> I understand.
>
> >> One thing that really annoys me is:
> >> arr.Add(new Foo(bar))
> >> doesn't work.
> >
> > It is by design too. I didn't want to make NEW a true operator. But it is
> > just a compiler restriction. The interpreter don't care.
> > For example, you can do
> >
> > arr.Add(New("Foo", bar))
>
> Oh.
> Why doesn't the compiler then allow it?
> If it is by design, why does the interpreter allow it.
> And what are the benefits from not allowing it?
>
> I'm sorry, but I really can't see any good reason for this :(
>
> >> another nice feature would be, if one could declare a variable inside a
> >> for statement:
> >>
> >> for i as integer = 0 to 10
> >
> > Same remark than before. And I don't see the benefit of having variables
> > "as local as possible". It will change nothing in interpreted code.
>
> We have really different religions :)
> One of my most important laws is "declare variables as local as possible"
>
> >> Why doesn't gambas do virtual dispatching?
> >
> > You are absolutely right. I just change the interpreter in the 2.0 so
> > that virtual dispatching work. As soon as I release the first
> > developmement version (1.9.1), you will be able to test it and tell me if
> > things are right.
>
> Thank you!
>
> >> I'd love to see the possibility to set the Tabstop ordering.
> >
> > TabOrder = ZOrder, so you just have to modify the second to change the
> > first.
>
> I'm sorry. I must have missed it in the documentation.
> Thank you!
>
> >> It would improve the usability of the IDE if I could create directories
> >> to store my class and form files
> >
> > I was thinking of letting the IDE show an ordered and hierarchical view
> > of forms, classes and modules, even if they are stored flat in the
> > project directory.
>
> Something like an "object browser"?
> Would be nice, but I'd like to set it also myself.
>
> Consider a large project that uses 5 different libraries written in Gambas:
> a library consist of classes, but these classes are not required to inherit
> from
> each other - so your object browser wouldn't display the libraries
> correctly (because
> it would split them).
>
> But I agree, an object browser would be great.
>
> >> a minor issue: the executale file of my project contains a lot of
> >> information that shouldn't be there
> >
> > Well. It is a point I didn't think about :-) I note it in the TODO list.
>
> Thank you.
>
>
>
> I'm glad that you took the time to answer my questions/suggestions.
> Even though we don't agree with each other everywhere, I hope you'll
> consider a few
> of my points for future version of gambas :)
>
>
> PS: sorry for answering this late, but I haven't work yesterday -> we had a
> public holiday
>
>

Did you see that Form.ShowModal() returns the integer value passed to 
Form.Close() ?

-- 
Benoit Minisini
mailto:gambas at ...1...




More information about the User mailing list