Skip to content
Kevin Brightwell edited this page Aug 26, 2015 · 1 revision
Clone this wiki locally

Each UCOSP participant is asked to log all the difficulties they have getting set up to understand Umple. This includes understanding how to model in Umple, using UmpleOnline, code that is difficult to figure out, and development tools that are hard to figure out, or don't seem to work properly. The more log entries added the more we can better get a grip on the usability issues with Umple, and the more we can help future new contributors come up to speed.

Log entries

NOTE: Entries are listed in reverse chronological order.

Mar 22nd

I have come up with a solution for issue 136 (on Google Code)/issue 234 (on Google Code).

The problem:

The issues in question concern the generation of Java code using variable arguments (the "..." notation, which I will call "var-args" from here on in). The use of var-args is a problem when:

  • the method parameters are incorrectly ordered due to inheritance, e.g. the subclass has the constructor signature

MentorSubclass(Student... students, String someNewAttribute)

(Var-args must always be the last parameter in a method.)

  • the class has more than one type of association that is populated by use of var-args, e.g.

MentorSubclass(Student... students, Student... gradStudents)

(A method may only have one var-arg parameter.)

Basis for my solution:

While it has been suggested that this problem can be solved through use of Java Lists (e.g. List<T>) rather than var-args, I've decided I prefer a solution that uses arrays for the following reasons:

  • It allows us to make as few changes as possible to the Java code generation in Umple. The changes necessary for my solution need only be made to the generateConstructorSignature method of the JavaGenerator class. (See below for more specific details of my solution.)
  • A method that has a var-arg parameter of a certain type (e.g. Student... students) will also, alternatively, accept an array of Students, and will treat the array equivalently to a collection of Students that were passed separately as var-args. Specifically,

new Mentor(mentorName, new Student[]{s1,s2})

is treated the same as

new Mentor(mentorName, s1, s2)

Both are legal way to provide arguments for a var-arg method. (I compiled and ran some test Java code to confirm that this is true.) This means that all Java setter methods that are currently generated to use var-args can be left as-is, even though arrays will be passed to the setters when those setters are used internally within class constructors.

  • It's easier to instantiate and populate arrays when you know the specific entities that are to comprise the collection. If we are using some type of collection that is being used expressly to pass arguments to a method, it would seem logical to use the one that is simplest to create. With arrays, one may simply call

new Mentor(new Student[]{s1,s2})

to pass two students to the mentor. If we were using lists, we would have to instantiate the list, then call the List's add(T) method for each student, then pass the list to the Mentor constructor. That can all be done in one line of code using an array.

  • Noted: If we don't want to have to know ahead of time how many entities there are in the collection, arrays are less convenient than Lists, but no less convenient than var-args. (This is one point on which one may argue that Lists are better.)

To use Java Lists, the jet templates for Java code generation would have to be changed extensively -- not just for class constructors, but also for the set-methods since those methods are used internally by the constructors to populate the collections of entities for mandatory relationships. Also, such a change in Java code generation would produce a massive number of changes to the generated code in Umple's very codebase. In sum, the number of side-effects would be HUGE. I'm not sure such extensive change will produce results that are worth it. (But I'm open to arguments to the contrary.)

My solution:

My solution works from the approach that var-args should still be used whenever possible, and when that's not possible, arrays should be used instead:

  • If the class has only one association that could be specified via var-args, the constructor will use var-args, and the var-args will be last in the list of method parameters.
  • If the class has multiple associations that could use var-args, the constructor uses arrays instead.
  • If the class has a parent class that uses var-args (i.e. the subclass sees that the parent signature has "..." in it), then
    • if the subclass has no additional var-arg-applicable associations, the subclass reorders its constructor parameters to make sure the var-args are still at the end of the constructor signature.
    • if the subclass has additional var-arg-applicable associations, the "..." in the parent's signature is replaced with "[]", and the subclass uses arrays.
  • If the class is a subclass, and it sees that the parent signature has "[]" in it, the subclass automatically uses arrays instead of var-args.

For a concrete demonstration, consider the following:

class ClassA
{
  name;
  * -> 1..5 SomeClass someClassA;
}

class ClassB
{
  isA ClassA;
  id;
}

class ClassC
{
  isA ClassB;
  * -> 1..5 SomeClass someClassC;
}

class ClassD
{
  isA ClassC;
  * -> 2..6 SomeClass someClassD;
}

class ClassE
{
  int[] integers;
}

class ClassF
{
  isA ClassE;
  int number;
  * -> 1..3 SomeClass;
}

The first four classes would have the following constructor signatures:

public ClassA(String aName, SomeClass... allSomeClassAs)

public ClassB(String aName, String aId, SomeClass... allSomeClassAs)

public ClassC(String aName, String aId, SomeClass[] allSomeClassAs, SomeClass[] allSomeClassCs)

public ClassD(String aName, String aId, SomeClass[] allSomeClassAs, SomeClass[] allSomeClassCs, int aNumber, SomeClass[] allSomeClassDs)

Notice how parameter reordering occurs as long as there is a "..." parameter to push to the end of the signature, but no reordering is done for association parameters that are specified with "[]". This means that for ClassD the association parameters start to get mixed together with attribute parameters.

The side-effect of the child-class looking for arrays in the parent-class's signature is that if the parent class simply has an attribute that is an array, that will cause the child-class to use an array instead when it could/should have used var-args:

public ClassE(int[] aIntegers)

public ClassF(int[] aIntegers, SomeClass[] aSomeClasses)

(One way to avoid the above inconsistency is to recursively check through the associations of the ancestor classes to see if there actually exists a var-arg-applicable association among the ancestors, to verify that the "[]" notation is being interpreted correctly.)

Variation: A variation on the above solution is to always allow there to be ONE var-arg parameter in the constructor signature, no matter how many var-arg-applicable associations the class has.

  • For example, if the parent class has a var-arg parameter, the descendant classes will have that same var-arg parameter, and it will always be the last parameter in the constructor's parameter list, for all descendants, forever after.
  • If the base class has multiple var-arg-applicable associations, either of the following solutions might apply:
    1. All but the last parameter will be arrays, and the last will be a var-arg. But if we do this we come to the problem of how users can go about defining which association they want to have as the last, var-arg parameter in the constructor, and what they can count on as expected behaviour in this case. Currently, I believe that Umple would treat the associations in the same sequence that they are declared in the Umple class definintion. So, if there are multiple var-arg-applicable associations, the last one would be the var-arg parameter in the constructor. But I don't think it's such a good idea to allow users to bank on this implicit behaviour.
    2. All association parameters are simply arrays, so that the class nor any of its descendants will ever have var-arg parameters.

At this time I'm not inclined to use this variation of the algorithm.

Mar 13th to 20th

In the past week I've done a lot of committing but not any logging of my activities, so here's an update on what I've accomplished.

  1. I finally committed my changes regarding immutability and inheritance. I found that my work was getting complicated by my getting hung up on holes in the Umple meta-model that could allow illegal circumstances to arise regarding immutability. Instead of trying to add logic to handle every case, I set upon simplifying the number of cases that could arise in the first case. For example, I realized that I could find no occasions except test cases where the AssociationVariable method setIsNavigable(boolean) was used; I simply made the AssociationVariable's isNavigable attribute immutable so that it could never be reset once it has been set in the constructor. Another example is that I made the setImmutable() method parameterless, so that an UmpleClass could never be made mutable again once it's been made immutable. Finally, instead of using the exact algorithm for propagating immutability through the inheritance chain that Tim and I discussed, I used one that made more sense to me, that I felt required less documentation and was easier to intuit by those reading the code, and that I believe doesn't lose much in the way of performance.
  2. I finished polishing the Java and Php jet templates in the way I described in an earlier log.
  3. I created the testbed tests for class-level immutability in the testbeds for all of Java, Ruby, and Php.
  4. I determined that the Cpp jet template changes and testbed tests for class-level immutability would have to wait until after the committer responsible for the Cpp development had made more progress in that aspect of the project, so that I could have more existing Cpp templates to work with.

While waiting for the opportunity to make the Cpp changes, I've done work on issue 286 (on Google Code) (immutable associations):

  1. I made the necessary changes on the meta-model, grammar, and parser level to ensure that associations can have the "immutable" modifier. I made a series of changes to the grammar, since I decided after my first commit of grammar/parser/model changes that my initial change to the grammar was too heavyweight and that I could accomplish what I needed to do in a much more elegant manner. Hence I made another commit that effectively reversed many of the changes that had been necessary due to the initial "heavyweight"-ness of those first grammar changes.
  2. I gave additional thought to reflexive associations, and decided to add a rule that reflexive associations cannot be mandatory. (This affects class-level immutability too, since by definition an immutable association must have an immutable class at the directed end, which means the reflexive association must clearly be contained within the immutable class.) Mandatory immutable reflexive associations clearly don't make sense since they result in a foolish chicken-and-egg object-creation dilemma, and I decided that the parser should simply disallow such associations rather than allow the user to generate code that is foolish and is nonsensical in the larger scheme of things.
  3. I created the Java, Php, and Ruby testbed tests for immutable associations. These tests were essentially identical to the tests for associations in immutable classes, and I felt that they were strictly not necessary since I know that the jet templates generate code for immutable associations the same way whether the association is immutable or the class is immutable. That said, I ended up feeling it was important to conceptually separate testbed tests for the two cases (immutable associations and associations in immutable classes) to ensure that no changes to Umple can be made that, for whatever reason, break one case but not the other. Perhaps the duplication of testing is excessive, but I still feel better knowing that testing is in place that makes no assumptions about how the implementation was done.

At this point, I feel that my work on immutability is done (until I work on the Cpp templates and testbed, that is). The issue that I am still most interested in addressing next is issue 136 (on Google Code) / issue 234 (on Google Code) (they are effectively the same issue). I personally encountered annoyance due to this issue in my previous work, and I'd like to contribute to a high-priority issue if I may.

Regarding how I would solve issues 136/234, my first inclination is to use arrays, rather than generic lists, as a replacement for the "..." notation since I believe arrays are easier to instantiate and populate than lists, which means there's less programmer/usability overhead due to the change in usage. I will spend my time doing some research and running some experiments to help me make my decision, and I will document my thoughts in this log. A part of me still wishes to maintain the "..." notation in all cases possible (e.g. in the setter methods) although I'm not certain that will actually be possible. (Nor how much that is even desirable, for the sake of consistency.)

Mar 7th

Regrettably due to ill health and a need for a lot of rest last weekend and the past few days I have been unable to make progress so far. I am feeling much better now, but I have one more upcoming midterm which I have to deal with, and which will take the most of my energy until the end of the week.

It looks like I will likely not be able to attend the hangout this Friday. I hope that will not be a problem though, since what status I have to provide is overall not different from what I reported at the last hangout. I expect to be able to make a lot more progress this weekend and in the following weeks since all of my midterms will be done and I won't have any major responsibilities in most of my classes for a couple of weeks.

Mar 2nd

Tim replied to my concerns with the following suggestions:

  Hi Sonya,

  Very good analysis. Here's my take and a suggested efficient 
algorithm.

  First, I think it is important to make sure we are all talking about 
the instances of umple metamodel classes and not the generated code 
when we talk about such things as making two-way associations to 
represent a generalization, for example.

  1. I actually don't see the problem of two-directional associations 
    to represent the superclass-subclass relationship. That is one of the 
    things Umple is good at. This is not run-time overhead, and the compile 
    time overhead is minimal.

  2. You are right that in most models, the inheritance hierarchy will 
  be small, especially when immutability is involved.

  3. I would avoid using special patterns like observer that Jordan 
    suggested until and unless we build them into Umple, with generated 
    code. And I don't think that is needed here. the Observer pattern is 
    useful when you have control of one side of the code base and not the 
    other. Here you have control of all classes in the metamodel.

  4. You could avoid repeatedly traversing a hierarchy by using 
    multiple states of the isImmutable variable as follows:
    * 'true' if all constraints have been checked (no violations in the 
      current class, superclasses, subclasses).
    * 'false' if there is a definite violation. No assertion of 
      immutability can be made.
    * 'inProgress' (temporary state during the algoritm see below)
    * 'null' otherwise (this is the initial condition.

  Apply the following algorithm

  1. When encountering a request to mark a class as immutable (either 
    because of encountering an immutable keyword, or use of the class in 
    an immutable association, or as a supeclass or subclass)
  * If isImmutable is true, return doing nothing, all is OK.
  * If isImmutable is false, there is an error. Stop.
  * If the class has an immutability violation, there is an error. Stop.
  * If isImmutable is null
     * Set isImmutable to inProgress
     * recursively try to mark the superclass as immutable
  - Recursively check the subclasses other than any with isImmutable marked 'inProgress' or 'true'
  * Set isImmutable of the current class to true.
  At this point isImmutable in all classes in the hierarchy will be true.

  2. when adding any kind of immutability violation to a class:
  * If isImmutable is false, break, (All is OK, just another violation).
  * If isImmutable is true, there is an error
     (you already have this case in the code you wrote)
  * (it must be the case at this point that isImmutable is null)
  * Set isImmutable to inProgress temporarily
  * Recursively mark isImmutable as false in the superclass and all 
    subclasses, except subclases where it is inProgress.
  * Mark isImmutable as false.
  At this point isImmutable in all classes in the hierarchy will be false.

  3. When adding a generalization relationship (linking two hierarchies 
    that may have different states of immutability).
  * If isImmutable in both classes is the same. All is OK. Stop.
  * If isImmutable in the subclass is true, then
     * If it is false in the superclass, it is an error
     * If it is null in the superclass, apply subalgorithm 1.
  * else if isImmutable in the subclass is false, then
     * If it is true in the superclass, it is an error
     * If it is null in the superclass, apply subalgorithm 2.
  * else (isImmutalbel in the subclass is null).
     * If it is true in the superclass, apply subalgorithm 1
     * If it is false in the superclass, apply subalgorithm 2

  4. When done all processing, check all classes marked immutable to 
    ensure the 'immutable' keyword is present in them, otherwise issue 
    a warning.

Which resulted in my following message, with Tim's responses interspersed:

> Hi Tim,
>
> Thank you very much for your detailed feedback. I've read the algorithm
> over a couple of times, I see the efficiency of it, and I believe I
> understand most of its subtleties. That said, there are some points I wish
> to examine in more detail to confirm that I understand things correctly:
>  *  If an UmpleClass is not ever marked as immutable, if it does not ever
>     have explicit immutability violations added to it, and if it is never
>     added to an inheritance hierarchy in which the other class's
>     isImmutable is not "null", its isImmutable will remain with the value
>     "null". Thus, when the isImmutable() method is called, both "null" and
>     "false" should be taken to mean "false".

Yes.

>  *  Regarding the algorithm's recursion through super-classes in
>     subalgorithm 1:
>      +  If the "true" value is communicated upwards to super-classes, to my
>         mind that has the effect that, when the "immutable" modifier is
>         added to a subclass, it also causes the super-class to become
>         immutable, even if the "immutable" keyword isn't explicitly
>         attached to the super-class; that is, a kind of reverse-inheritance
>         appears to take place.

OK. At the M2 meta-level the concept is a little different than at the 
M1 modeling language level (to use MOF terminology).

Inhertance that we normally think of is an M1 concept that causes 
things to happen at run time.

Here we are talking about am M2 concept that causes things to happen at
compile time. In other words, we are interested in triggering warnings 
and errors, and only after all is done, setting up code generation of 
the M1 level code.

Let's use the case where we are building classes S (superclass) and T 
subclass. If we encounter 'immutale' in class T, but S has a violation 
then it is clearly an error. If S doesn't yet have a violation, then we 
simply want to say: "If S ever gets a violation through code that we 
parse later, then we have an error". And the same is true in the 
inverse.

This isn't quite the same thing as 'inheritance' since at the M2 level 
what will eventually (at M1 level) become a generalization, is being 
modelled just as a special association.

>      +  I agree that warnings should be issued when subclasses are caused
>         to be immutable by their super-classes when the subclasses don't
>         also have the "immutable" modifier explicitly attached. The warning
>         would be to the effect that "Perhaps you want to add the immutable
>         modifier to this class to make the fact that this class is
>         immutable more explicit". But I feel that something different
>         should occur if the metamodel exists in a final state in which an
>         immutable subclass requires its superclass to be immutable, but the
>         "immutable" modifier hasn't actually been attached to the
>         superclass.

OK. If the superclass doesn't have any violatins (e.g. it just has 
abstract methods etc.) but the superclass doesn't then there is no need 
even for a warning. So I agree, adding the immutable keyword in a 
superclass is not always needed.

>      +  To address those two points above, I'd like to suggest an
>         alternative to the recursion through superclasses that is suggested
>         for subalgorithm 1:
>          o  I would add an additional state to isImmutable: a 5th state
>             indicating that "I am trying to be immutable but I'm waiting
>             for confirmation from my superclass that I can be immutable".
>             It would be considered a temporary state, but less temporary
>             than "inProgress" since it could persist between different
>             parts of the 4-part algorithm you outlined. It may even persist
>             until post-processing checking, but should it do so, it would
>             be an indication of error.

This sounds reasonable.

>          o  This 5th state would be a variant of "true", and in many cases
>             in the 4-part algorithm it would be treated as though it has
>             exactly the same meaning as "true":
>              o  it would result in an error when it is encountered in
>                 subalgorithm 2.
>              o  In the case of being the superclass in generalizations, it
>                 would result in the exact same behaviour as if it were
>                 "true". (i.e. "null" subclasses are changed to "true",
>                 "true" subclasses are left alone, "false" subclasses result
>                 in an error).
>          o  In subalgorithm 1, no checking of superclasses would be done.
>          o  *successful* execution of subalgorithm 1 would result in all
>             sub-classes having an isImmutable of "true". The UmpleClass at
>             which subalgorithm 1 was rooted will EITHER have isImmutable of
>             "true" (if the UmpleClass is the root of the currently-known
>             hierarchy), OR it would have isImmutable of this 5th state (if
>             the UmpleClass is a subclass in a generalization).
>          o  This 5th state would be overwritten by "true" whenever it is
>             encountered in subclasses within subalgorithm 1.
>          o  It would be expected that, in a correct program, this 5th state
>             would have been overwritten with "true" by the end of parsing
>             the metamodel, as a result of an ancestor having been made
>             immutable and subalgorithm 1 being executed.
>          o  If, during post-processing checking, a class that still has
>             state 5 was discovered, this would result in a compilation
>             error, to the effect that "An immutable class cannot extend a
>             mutable class".

Yes, all this sounds reasonable.

I suggest documenting the whole immutability checking algorithm, 
including the 5th state 'truePendingConfirmation' as an enhanced 
version of what I wrote, and add it as a wiki page. Then reference that 
page in the code.

- Tim

Feb 29th/Mar 1st

Having dealt with some midterm exams, I'm now back on the Umple train, and I've been dealing with the issue of class immutability and inheritance. I have some design decisions I'd like to run by others, since adding certain changes affects the "completeness" of the meta-model, but they also would have some efficiency implications for the compiler.

The design decisions relate to the following "problems":

  • If a subclass inherits the immutability of a superclass, and if there are long chains of inheritance, every time isImmutable() is called on any member of a class (e.g. Association or Attribute), then the the call will traverse the entire chain of ancestors before determining for certain that the member is NOT immutable. (If the member IS immutable, likely not as much recursion will be needed because the answer will often be found "closer to home".)
  • If a relationship has been created between a mutable superclass and subclass, and the subclass has members that don't support immutability (e.g. state machines or the wrong kinds of associations), then if later the instruction occurs that the superclass is immutable, that should result in a compilation error.
  • currently superclasses don't know about the classes that extend them. Only subclasses know about their superclasses.

My concept for solving these issues is that:

  • superclasses should know about their subclasses. That way, superclasses can inform subclasses when they've changed, and subclasses can perform the necessary checks to determine whether that change causes "illegal" situations to arise, and then report back to the superclass about whether everything is still ok. This change also means that a subclass can store a local field indicating whether it has an immutable ancestor, and never have to worry that the value of that field will ever become out of sync with the ancestors's actual immutability, so the recursion for each call of isImmutable() is eliminated.

The factors that go against this particular solution are the following:

  • The direct result of making the association between superclasses and subclasses bidirectional (i.e change 1 -> 0..1 UmpleClass extendsClass to * subclasses -- 0..1 UmpleClass extendsClass) is that all superclasses must now maintain a list of their direct ancestors. This is a space versus time tradeoff, and I'm inclined now to think that in the case of a compiler that may potentially be compiling very large programs, memory is a valuable resource that I shouldn't be quite so willing to spend in this way.
  • My solution assumes that inheritance chains are a common thing, when they may actually be rare, so my solution may actually be more "expensive" overall, since classes would now be carrying around useless, extra pointers to empty ArrayLists of all their non-existent subclasses.
  • My tests of the parser appear to indicate that file content is never parsed in such an order that a superclass will be modified after its subclass has been added. Not even in the following case:
        class SuperClass
        {
            int counter;
        }

        class MutableClass
        {
            isA SuperClass;
            1 -> * OtherClass;    // illegal association for an immutable class
        }

        class OtherClass
        {
        }

        class SuperClass
        {
            immutable;
        }
  • In the above case, the particular parser error that occurs is one saying that immutability rules prevent MutableClass from subclassing SuperClass. The fact that that particular error occurs indicates that all information regarding SuperClass has already been parsed (e.g. SuperClass has already been made immutable), and also that all association between MutableClass and OtherClass has already been parsed, before the parser puts in place the inheritance connection between MutableClass and SuperClass.

I could make evidence-based assumptions about how the parser is going to behave, and streamline/optimize my code so as to deliberately not cover the case that a change is made to the superclass after its subclasses have been added. My code could assume that once the connection between a superclass and subclass is made, the superclass will not change. This would eliminate the need for superclasses having to know about their subclasses and notify them about immutability changes. I don't have complete, 100% confidence that the parser couldn't be made to change some aspect of the superclass after subclasses have been added, I only know that this is what appears to be the case for the behaviour I've been able to evoke so far.

There is the potential that I could roll back many of the changes I've made and leave only the bare essentials of what appears to be necessary for the test cases I've been able to identify. But the part of me that prefers logical completeness (and prefers a lack of hidden dependencies between parser elements) is uneasy with that course of action.

Feb 25th

On Feb 22nd Tim notified me that adaptations need to be made to my immutability code to account for inheritance issues:

"The following code, however violates the immutability constraint. Z inherits stuff that is not immutable. Presumably a subclass can only be marked immutable if its superclass is immutable or is empty (e.g. has only abstract methods, constants etc.)."

class X {
  Integer m;
}

class Y {
  s;
  1 -- * X;
}

class Z {
  isA X;
  q;
  immutable;
} 

I have been slowly working on the issue since then. I've had to spend the bulk of the last several days on studying for a physics exam as well as dealing with some other things and I haven't had long solid periods to work on Umple. For that reason I'm making changes on this issue slowly and carefully because my train of thought is having to be broken often. The main thing that I'm thinking about is the matter of long inheritance chains and knowing whether a class's ancestor is immutable. I've decided to add some optimization so that it's not necessary to trace all the way up the class's inheritance chain to determine if a class is immutable every time isImmutable() is called. I'm trying to make the optimization clean and as simple as possible, so I'm taking my time and re-polishing my concept every time I have a chance to look at the problem.

Feb 21st (2)

I was just browsing the Umple site trying to remember where the list of revisions was, and I came upon the Test report site, which I wasn't aware of before. I notice that some of the php tests are failing. ("49/49 test cases complete: 1746 passes, 2 fails and 3 exceptions.") It would seem that some of my changes to the php generation, in my earlier commit, affected testbed_php tests. I've only been checking the cruise.umple QA report when building locally, but now I've learned my lesson that I should be checking the other reports as well. Fixing the problem will be first on my priority list before the other tasks I listed below.

Feb 21st

I am just about ready to commit my changes to the ruby code generation. In the process of making my changes, I discovered a problem in the ruby template for lazy immutable attributes that was preventing the setter from genuinely enforcing immutability. For example:

return false unless @can_set_name
can_set_name = false

This is the code that is supposed to prevent the setter from being successfully reused after the first time the lazy attribute has been set. The problem is that @can_set_name and can_set_name are different variables - the first is the instance variable, and the second is a local variable that is inadvertently created as of the moment of that assignment statement. I made the fix so add the @ on the second line, which means I also had to fix the expected output in a number of output files not related to my changes.

Through the email conversation with Adam over his SQL patch, I've become aware of the testbed tests, and realized that these are what are used to confirm that the generated Java, ruby, php, etc... code actually functions in the way that it's supposed to. As a result, I've realized that to finish issue 241 (on Google Code) I have a few more things to do than I realized:

  • write testbed tests for:
    • the ruby bug for lazy immutable attributes that I just fixed
    • associations and attributes (including lazy attributes) in immutable classes in:
      • Java
      • php
      • ruby
      • cpp

This is in addition to committing the ruby code generation patch and doing the cpp code generation patch that I had already been planning to do.

I find that as I edit the JET templates for each language, I learn more things, and as a result I go back and change some things I did in the set of templates I modified for the previous language. In this case, I realized while working on the ruby templates that there was a much better, cleaner way that I could do that check for immutability in setters for associations, e.g a check like:

return false unless @can_set_mentors
@can_set_mentors = false

The way I insert that block of code is much less attractive in the Java and php JET templates than I did it for ruby. As a result, going back and making those changes is also on my to-do list.

I had been hoping that I could finish my work on issue 241 (on Google Code) this week and move on to other, higher-priority fixes (e.g. issue 136 (on Google Code)/issue 234 (on Google Code), or issue 273 (on Google Code)), but it looks like that won't be the case. In spite of the long time and great deal of work it's taking, I'm glad I took on issue 241 (on Google Code) since it's been teaching me a lot about the umple compiler and test suite, from top to bottom, which is what I hoped would happen.

This is my action plan for the next number of commits (each item is a separate commit):

  1. Java testbed tests (immutable class with each type of association, with attributes, and with lazy attributes)
  2. make improvement to Java templates that I did to ruby templates
  3. php testbed tests (immutable class with each type of association, with attributes, and with lazy attributes)
  4. make improvement to php templates that I did to ruby and Java templates
  5. ruby testbed tests (immutable class with each type of association, with attributes, and with lazy attributes; lazy immutable attributes)
  6. cpp codegen tests and changes to cpp JET templates
  7. cpp testbed tests (immutable class with each type of association, with attributes, and with lazy attributes)

I contemplated trying to do the testbed tests first in the last two items listed above, but I think my changes to the jet templates are more effective when I'm inspecting the generated code so closely like the codegen unit tests involve. I think it would be harder to make quick progress if I did the testbed tests before the codegen tests.

Feb 20th (3)

I committed my changes to the php code generation so that immutable associations are now represented correctly in php too.

I found making these changes much faster and easier than making the java changes since much of this work was just duplicating the same process of changes I'd made to the Java templates. The main concern was that I had the php syntax correct since it's been a while since I've used php and I'm not as alert to the syntactic subtleties. I feel pretty confident my changes are correct, since they don't have much syntactic complexity, and equivalent syntactic situations already existed in the php JET templates so that I could refer to them when I was in doubt.

Feb 20th (2)

I created issue 279 (on Google Code). I was mulling over the issue of "add" and "set" methods that did or didn't enforce uniqueness. I was somehow under the impression that they enforced uniqueness on some occasions and not others. I was about to report an issue for that, but I realized I was wrong and that uniqueness appears to always be enforced, and as a result I need to go back and change my code, in my recent commit, where it should report more clearly if all entities passed to the setter method are not unique. In any case, over the course of that investigation I came upon the insight that I've reported in issue 279 (on Google Code).

I realized that lazy associations in immutable classes weren't generating correctly, and my tests had neglected to check code generation for lazy associations. Apparently, when I'd done the refactoring so that all occasions of "immutable".equals(av.getModifier()) were changed to av.isImmutable(), I missed an occasion when the check was essentially the same but the code was stated differently. I had to make the fix in the generator code for each language, and I created tests to confirm that the fix took effect.

I've committed those changes, so finally I believe I can work on php code generation undistracted by other issues. I'd already been working on php today, but I had to temporarily rollback those changes when I became aware of the needed fixes for the Java templates, which I considered a higher priority to commit first.

Feb 20th

The changes have been committed. The midterm break has been good for my Umple contributions, since I'm lucky to have a number of days over which I am able to spend time on little other than Umple. Of course, starting Wednesday I must commit a great deal of time studying for my physics exam, so my Umple work will unfortunately drop off significantly then.

I consider the following to me the most significant points for critique:

  • My approach regarding the inclusion of OPTIONAL association members in the constructor. This contrasts with the current usual treatment of optional associations in the constructor in Umple, i.e. the fact that parameters for those associations are NOT included in the constructor. I felt that for immutable objects, this data should be passed to the constructor, even when it's optional. This had interesting implications to issues I had to consider:
    • Sometimes the user will want to provide an empty set for an optional association. The current convention is to use variable arguments (e.g. "Student... students") for "To Many" associations. For optional associations, passing a null value to variable arguments will generate a compiler warning, as in this example:
Test.java:6: warning: non-varargs call of varargs method with inexact argument type for last parameter;
Student s = new Student("Cynthia", null);
                                    ^
  cast to Mentor for a varargs call
  cast to Mentor[] for a non-varargs call and to suppress this warning
1 warning
* The program does still compile and function. I had my thinking stuck in the understanding that, if a person wanted to provide an empty set to the varargs, they'd have to provide "null" to the constructor. I implemented checks in the constructor (or rather the setter - see below) for a "null" collection since otherwise a NullPointerException would occur. Clearly I was too locked in this thinking and don't have much experience with varargs, since it didn't occur to me until after the commit that simply providing NO values to the varargs would result in the most desirable empty array (rather than a null pointer), which would not cause a null pointer exception. I intend to commit another change right away to remove the unnecessary check for null.
* Currently the convention is for the class's constructor to use the class's existing "set" method to set any association data passed to the constructor. My immutable classes continue the same convention, but the setter's access modifier is now set to private so that the setter is only an internal method. Since I assumed a setter is being used to set optional associations that have been given the value "null", the setter checks that the collection is not null - instead of throwing the usual NullPointerException. I've realized it's not necessary to pass "null" for empty collections, so as stated above, this check will be removed.

Feb 19th (2)

I am nearly ready to commit my complete set of tests and changes to the jet templates for Java code generation that ensures that immutable associations have the correct accessors, methods, constructor parameters, etc. I have tests for each kind of unidirectional association that an immutable class may use, and all tests are currently passing. I'm going over everything again with a fine-toothed comb, however, to be certain my changes are conceptually correct.

The main issue is the question of variable parameters and what happens if you pass "null" into them. This is a concern for the private setter for "Optional To Many" associations. This setter is in most ways the same as the ordinary setter, just with the "private" access modifier. If the parameter is optional and the user wishes to pass "null" as a parameter, I wish no problems to be caused.

Feb 19th

On further thought, I've decided just to settle with "wrong" constructors for my immutable objects for now. I looked more closely at generated constructor code and noticed that there would be some added complexity to how the collections would have to be handled once passed into the constructor, since they could no longer just be passed on to the class's "set" method for that association. (You can't pass a Collection to a method with a variable parameter.) A separate private setter method would have to be created, or the existing setter method would have to be modified to handle collections instead (less desirable imho).

I will consider requesting to work on issue 136 (on Google Code) and issue 234 (on Google Code) after I'm done dealing with immutable classes.

Feb 18th

Today I finished my modifications to prevent state machines in immutable objects, and I committed some changes.

I find I'm thinking back on my previous two patches and contemplating whether I should have made some of the changes as "comprehensive" as I did. I find myself wondering if I'm bulking up the meta-model and compiler classes too much. The changes I made were as such because I wanted to make the changes conceptually complete -- I didn't want there to be buggy ways that the rules about immutable classes and associations could be circumvented in the future. I wish for feedback on this point.

To Many Associations

I'm currently working on changes to the code generation so that the immutability of associations is genuinely enforced. I find myself contemplating the case of unidirectional "To Many" (i.e 1 -> *) associations.

Currently Umple generates code, if a "To Many" association exists, such that the members are set through a setter only - not the constructor. This is understandable since the many is an optional association - it could be zero as easily as it could be more than zero - and it's annoying to have an extra parameter in the constructor if the user is just going to pass in "null" or an empty collection.

I firmly believe that, in the case of "To Many" associations in an immutable class, the association members MUST be set in the constructor.

I recognize that how I choose to solve this problem is very closely related to existing Umple bugs. Umple currently generates Java code that specifies association collections with a variable parameter (e.g. Student... students), but if a class has more than one "To Many" associations, it would be illegal Java syntax to have more than one variable parameter. Umple generates broken Java code in the case of multiple "N to M" associations (see issue 136 (on Google Code) and issue 234 (on Google Code)). Example code:

class SomeClass
{
  1 -> 1..* OtherClass;
  1 -> 1..2 ThirdClass;
}
class OtherClass
{
}
class ThirdClass
{
}

results in the broken Java constructor

public SomeClass(OtherClass... allOtherClasses, ThirdClass... allThirdClasses)

Clearly the solution is to use some kind of "collection" object instead of a variable parameter. I would like to determine the best type of Java collection that should be used to pass objects for "To Many" associations to the constructor of an immutable class. The following possibilities exist:

  • simple arrays.
  • UnmodifiableList<T>, in which case the private list for the association members could just be set as the UnmodifiableList without even having to iterate over and copy the contents of the list to a private list. But then the user must go to the trouble to create the UnmodifiableList in the first place.
  • Generic Collection<T>. This same solution could also be generalized to fix the broken constructor problem above, and could be used as the general Umple solution for passing multiple collections to Java constructors. This would seem to be the preferred solution, not least because it allows the user to choose among a large number of subclasses of Collection. Generics provide type-checking so that the constructor doesn't have to worry about the implications of type-casting.
  • Iterator, Enumeration, and non-generic collections seem less than desirable to my mind, since they cause more work (to both the user and to the generated code).

I've realized that making that possible would also effectively fix issues 136 and 234. (See, for example, the method "generateConstructorSignature" in Generator_CodeJava.ump, where one change would effectively fix the constructor for all cases.) This would mean my fixing multiple issues simultaneously. I could just settle with "wrong" constructors for my immutable objects and defer fixing issues 136 and 234 to a later date, or I could work on the higher-priority 136/234 immediately and return to the matter of immutable classes after.

Feb 17th

After repeated testing and tweaking of some details, I've committed the patch and it built successfully. I found the last steps exhausting since I found myself thinking over a lot of little details and rethinking certain design decisions - not major decisions, just ones that someone wants to make things absolutely perfect would stress over. At this point I think I've got to let go of my design decisions and wait for possible feedback from code review. I think the fatigue/stress is one of the side-effects of making such a large patch, i.e. the number of details became a little overwhelming. I think having to make this large one was part of the learning process, but I wish future patches to be smaller and much more frequent.

As for the next step: I'm not changing code generation just yet. I'm sidestepping into other meta-model and parser-level stuff first, specifically the matter of preventing immutable classes from having state machines, since making those changes is so similar to the other ones I've already made so far and I think I can make quick progress with those changes.

Feb 16th

I am testing and preparing to commit the patch. It contains (and tests)the following features:

  • AssociationVariable has isImmutable() method which checks if the related association variable or either UmpleClass (if relevant) is immutable. Uses of "immutable".equals(av.getModifier()) have now been replaced with av.isImmutable().
  • The association between AssociationVariable and UmpleClass is now bidirectional.
  • setUmpleClass for AssociationVariables, and setAssociationVariable for UmpleClass, does a check if the class is immutable and if the AssociationVariable (and related association variable, and its umple class) together form a configuration that adheres to immutability rules.
  • The AssociationVariable methods setIsNavigable and setRelatedAssociation do checks on whether those changes are legal in light of whether attached UmpleClasses are immutable.
  • The UmpleClass method of setImmutable checks whether that action is legal in light of the associations the class has.
  • The parser is tested that the correct types of associations are allowed to be created, and invalid associations fail to parse.
  • Cases are handled for inline associations, symmetric associations, independently-defined associations and association classes.
  • Specifically the following rules apply for immutable classes:
    • no bidirectional associations allowed for immutable classes, and thus an immutable class can't participate in an association class.
    • immutableClass -> immutableClass is allowed
    • mutableClass -> immutableClass is allowed
    • immutableClass -> mutableClass is NOT allowed

The patch does not do the following:

  • change generated code output
  • define the rules for immutable associations (as compared to just the associations allowed for immutable classes)

Feb 13th, 14th, 15th

I have been working steadily at the support among associations for class-level immutability. My plan was to make the changes to the meta-model (and add the tests), and then also modify the parser (and test it) to make sure the parser and the meta-model were interacting correctly regarding the new restrictions on associations.

I've made alterations to AssociationVariable and UmpleClass code to support the enforcement of association restrictions. It has been slow work since there are many cases for me to identify, and I have to identify all areas in the Parser that behaviour needs to be altered slightly to check return values when an an AssociationVariable is added to an UmpleClass. It took me some time to understand error handling as it's set up in the parser, and exactly what was happening in the error.en file. I'm finding that I've had to add a bit more code than I expected since there are multiple places in the code where immutability + associations needs to be treated correctly, and I've had to spend a fair amount of time debugging and realizing paths through the parser that I hadn't thought of beforehand. The parser has a fair amount of complexity, so I'm not bothered by the amount of time spent debugging since doing so increases my understanding of the parser.

I don't have much to report on my progress, other than the fact that I am making progress and hope to commit a patch soon - hopefully a day or two. I have a working build at this time, but I still wish to go back and refactor my code, as well as ensure I actually have covered all important paths through my code. (After having written my tests, implementing the code brought my attention to additional cases that I ought to be testing.) Also, I still have to make sure symmetric reflexive associations and non-inline associations are handled correctly. I have also thought of Association Classes as something I may need to handle.

Over all this patch is resulting in more code than I had expected. I made the choice to modify the meta-model and parser in the same patch, since I felt I needed the assurance that my changes to the meta-model were indeed appropriate to how the parser needs to interact with the meta-model. I'd prefer if I could have committed something smaller sooner, but I feel that taking such a large bite at once was important to ensuring that I was submitting a good-quality patch that deals with all the subtleties appropriately.

Feb 11th

Valid associations for immutable classes

In light of the fact that the attribute behaviour I described below is being considered a bug, I return to my original opinion that the following associations are the only ones that an immutable class may participate in:

 immutable -> immutable
 mutable -> immutable

Also if the "lazy" keyword is defined for associations:

 lazy immutable -> immutable
 lazy immutable -- immutable

There may be question about whether, in a bi-directional association, the "lazy" keyword applies to both ends rather than just one. I will leave that open for now, though the keyword could potentially be used to apply only to the end that it modifies, meaning that the following cases would generate slightly different code:

 lazy immutable -- immutable
 lazy immutable -- lazy immutable

The generated code for these cases would be analogous to that for associations. When the "lazy" modifier is used, the associations can be created via a one-time-use setter; otherwise, the members of the associations must be defined upon object creation.

Valid immutable associations in general

When an association is immutable, the members of an association MUST be defined in the object's constructor, unless the association is "lazy". Therefore, until the "lazy" modifier is added to associations, immutable associations may be uni-directional only.

In my opinion, immutable associations do not require immutable objects. This is where immutable associations, in themselves, differ from associations that support class-level immutability. Immutable associations may be between mutable objects, and the "immutable" part simply describes the fact that as soon as the association is made, it can never be changed for the lifetime of the associated objects.

Immutable associations already exist in Umple, in the form of Mandatory associations, e.g. 1 -- 1 associations. Since it is impossible to change the associations in such a case without orphaning an object at one end of the association, such associations cannot be changed once they have been formed. Adding the "immutable" keyword would simply serve to make Optional associations immutable as well, e.g. * -- 1 or 0..1 -- 1.

Again, as described above, when the "lazy" modifier is used, the associations can be created via a one-time-use setter; otherwise, the members of the association must be determined upon object creation.

My strategy

I will add ONLY that support to "immutable" associations that relates to class-level immutability. In that way, support for immutable associations in general will be created, but not completed, since there are a number of extra steps that will need to be taken to account for ALL use-cases of immutable associations. I will not add "immutable" to the grammar for associations until I'm certain those extra steps have been put into place (if that occurs before the end of my UCOSP term). I suspect pure immutable associations are a very low priority over all.

All discussion regarding the "lazy" modifier for associations is currently hypothetical. Its possible inclusion in the grammar will be addressed in a later iteration of issue 241 (on Google Code).

Feb 10th (2)

Tim suggested I do some further analysis regarding what associations are permitted to be immutable, rather than simply going by what is stated in the description for issue 241. I will separately address the types of associations that I think an immutable class may be part of, and the types of immutable associations that I think may exist in general, since I think those may be separate and different things.

Associations that make sense for an immutable class:

 immutable -> immutable
 mutable -> immutable

BUT NOT
 immutable -- immutable
 mutable -- immutable
 immutable -> mutable

ALTHOUGH POSSIBLY
 lazy immutable -- immutable

(this last point is not really relevant at this time since "lazy" cannot currently be applied to associations)

Types of Associations that may be immutable:

(list to be completed at a later date)

While researching this second list, I found and reported some bugs in Umple Online, including issue 273. I also came up with some points and conceptual questions regarding the current behaviour of immutable attributes:

I'm having some conceptual issues with the fact that there is no assurance that an immutable attribute is an immutable type of object, nor assurance that it is in any other way protected from alteration. For example:

    class Student
    {
      immutable List<SomeType> names;
    }

There is neither an enforcement that List must be an immutable type, nor that SomeType must be immutable, nor a deep copy made of the List and its contents, nor any other measures taken to protect the contents of the List from being meddled with. Are there any plans to change this, or has there already been much discussion of this issue? I know this is opening up a can of worms, but seeing as how I'm currently trying to approach the problem of class-level immutability from the perspective of conceptual "correctness", I feel the need to open the can. For interest's sake, here is an example of the generated code:

    public class Student
    37.{
    38.
    39.//------------------------
    40.// MEMBER VARIABLES
    41.//------------------------
    42.
    43.//Student Attributes
    44.private List<Name> names;
    45.
    46.//Helper Variables
    47.private boolean canSetNames;
    48.
    49.//------------------------
    50.// CONSTRUCTOR
    51.//------------------------
    52.
    53.public Student(List<Name> aNames)
    54.{
    55.names = aNames;
    56.canSetNames = false;
    57.}
    58.
    59.//------------------------
    60.// INTERFACE
    61.//------------------------
    62.
    63.public List<Name> getNames()
    64.{
    65.return names;
    66.}

I think the fact that immutable attributes behave this way, and if they are intended to continue behaving this way, is a good reason to argue that immutable objects can participate in the following associations:

 immutable -> mutable
and possibly even
 lazy immutable -- mutable

Feb 10th

Point (2) (from my list on Feb 9th) has made further progress but is not yet complete.

Feb 9th

The next stage is to allow Associations to be immutable, and to enforce the correct relationship between immutable classes and the types of associations they may have. I have determined the steps I intend to take in this process:

  1. Allow Associations to be immutable at the level of the meta-model.
  2. Add logic to the meta-model that ensures an error/exception will always occur when an illegal association is constructed involving an immutable class.
  3. Add any extra handling code in the parser for when an error is encountered. This should be fairly superficial logic since the bulk of the logic enforcing "correctness" should be in the meta-model!
  4. Make modifications in the JET templates so that correct code is generated in each language for immutable associations.
  5. Add the "immutable" keyword to the grammar as a valid modifier for associations. (This is a tiny bonus that comes as a result of all the support for class-association immutability that was done before now. I consider this to be the last step since I don't wish to make it a visible part of the grammar until all the changes to the code-generation by the JET templates is complete and correct.)

I intend to do (1), (2), and (3) as a single patch/commit. That means that the support for immutable associations will be set up in the meta-model but will not yet have any visible impact on the grammar or code generation. I expect (4) to be a series of separate commits, 1 for each language, though I'll need to understand better what's going on in the JET templates to be entirely clear on the number of different changes this will take. Finally, (5) will be the last, tiny commit.

I've already completed point (1), and am a little way through point (2).

After the 5 points listed above have been completed, I will still need to deal with some other concerns related to class-immutability such as state machines, etc.

Feb 7th

I've simply spent some time analyzing the steps I need to take next. I won't report on them until I have a clearer idea of what I intend to do.

It looks like, to make associations immutable, I need to add the immutability support in the meta-model to the AssociationVariable object since that is the only object that the JET templates access or analyze in order to generate code related to associations.

Feb 6th

Submitted patch to umple-dev with following explanation:

Here is the patch that I have been sitting on for the past week. This patch contains few changes that have been made since the UCOSP weekend (other than making some failing tests pass), but looking at the diff it is a substantial patch for reasons I explain below. I intend future patches to be smaller.

The patch includes these changes:

  1. UmpleClass now has an "immutable" attribute with getter and setter.

  2. Attribute now has isImmutable() method to check if the Attribute has the "immutable" modifier, instead of having to check value of the "modifier" attribute directly to determine whether an attribute is immutable. The method isImmutable() also checks the Attribute's associated UmpleClass to determine if the UmpleClass is immutable (which would cascade to make the Attribute immutable too).

  3. the constructor for Attribute now takes an UmpleClass since it's now necessary for an Attribute to know which UmpleClass it's associated with.

  4. MethodParameter is no longer a subclass of Attribute since a MethodParameter should not be associated with an UmpleClass in the way that an Attribute is now required to be.

  5. Test cases added to test "immutable" property of Attribute and UmpleClass

  6. "immutable" keyword is added to the grammar under the definition for "softwarePattern". Test case added to ensure the additional keyword is parsed correctly.

  7. the expected generator output, in 002_umpleGrammar.html, has been modified in order that the Generator test passes now that the additional grammar rule has been added.

NOTE: no changes have been made yet to support the immutability of Associations, or to restrict the types of associations that an "immutable" class may have. Currently an "immutable" class simply forces all attributes of that class to be immutable.

MOST changes contained in the diff are due to refactoring for the following reasons:

  1. In cases where the check for "if ("immutable".equals(av.getModifier()))" was done, it is now replaced with "if (av.isImmutable())".

  2. In all cases where the Attribute constructor is used, the code was modified to ensure that a reference to an UmpleClass is being passed to the constructor. Also, most calls to UmpleClass.addAttribute() have been eliminated where they were redundant since the UmpleClass is already passed to the Attribute constructor.

-Sonya

Feb 3rd

I've realized, in discussion with Andrew, that I may be putting the cart before the horse.

This was his response to my questions:

"I see it as the following features

  1. An immutable class makes any element within it immutable, which is currently only attributes
  2. Allow associations to be immutable
  3. Ensure that an immutable class is updated to support the newly created immutable associations"

In clarifying the meaning of his response, I've realized that the intention was to communicate that I should break up the issue into small, separate parts. Up until now I've been trying to resolve all goals in issue 241 which is why I've been confused by the message I've been getting that what I have left to do is very little and/or very easy, when what Andrew has really meaning to say that the work I've done up to now is a sufficiently complete step to submit it as a patch before I take on other parts of this same problem.

Feb 2nd

At this time I've narrowed in on the UmpleInternalParser code for analyzeInternalAssociation() and sub-calls to analyzeAssociation(). Somewhere in this neighbourhood is where I suspect my changes need to be made. The parameters to analyzeAssociation are the association token and the NAME of the class to which the association belongs, and for that reason, when the code is doing in-depth analysis of the association and whether the association is valid, there is no immediately apparent capability for me to check if the classes at either end of the association are immutable since I have their names only, not the actual meta-model of the classes. I suspect I may need to use some sort of getClass method of the UmpleModel to make those checks.

And now, looking into these methods, I understand how error reporting is to be done. (See, for example, the blocks of code for if (!myMult.isValid()) and if (!yourMult.isValid()) inside UmpleInternalParser.analyzeAssociation().)

As for how to test my changes, I would be first inclined to put my tests in UmpleInternalParserTest, but I don't see any precedent in that set of tests for testing for failure, which is what I will want to do. I will have to look further into this.

On a related note, in my search for answers about how to enforce the association rules, I put the following code in UmpleOnline to check if it would fail to be parsed:

class Student
{
}

class Mentor
{
 singleton;
}

association {
 3 Mentor -- 3 Student;
}

As far as I'm concerned, this qualifies as broken code since it requires more than one Mentor in the association even though Mentor is a singleton class, but UmpleOnline accepts it and parses Java code for it. I'm inclined to report this as a bug.

Feb 1st

I've been spending much time looking over the code base trying to determine what to do next. I've been contemplating the following 4 points of Issue 241.

  1. No -- (bidirectional) associations
  1. Outgoing associations -> only allowed to other immutable objects.
  1. Incoming <- associations allowed.
  1. No state machines (since no ability to change attribute values).

As I understand it, I simply need to make sure the parser protests, fails to compile umple code, and returns appropriate error messages when a user attempts to create immutable class that violates the rules stated above. I've followed method and field references up and down through the code for the Parser and Generator classes (and am happy for the insights they've provided me about the inner workings of Umple compilation and code generation) but I've not yet encountered the area of the code that I understand to be the place I should be making changes. I've found places where UmpleCompilerException are found, but the vast majority of them are in the Generator classes for specific languages, so I believe I've gone much too far into the compilation process. I believe the logic I'm looking for (and looking to add) should come well before the compiler is dealing with specific languages.

Also, because I'm not certain where to be making these code changes, I'm also not certain where I should be putting the tests that appropriately test for parsing failure and success for Umple code that violates/adheres to the rules listed above. I still hope to figure this out for myself since I believe I understand the bigger picture better by doing this digging, though I admit that it may soon be time for me to start asking questions.

Jan 31st (2)

Recall the failing test:

Assert.assertEquals(true,model.getUmpleClass("Student").isImmutable());

I was able to effect the changes to the parser such that the meta model was being generated correctly and the assertion passed. This was done by adding the handling code for the "immutable" token in the analyzeClass method of the UmpleInternalParser.

I ran a build to confirm that it passed, and noted that under the template.test target, the following failure occurred:

[junit] TEST cruise.umple.docs.DocumenterTest FAILED

I investigated and fixed the failure by adding the changes I'd made to the grammar to the 002_umpleGrammar.html file so that the actual documenter output (which already contained my changes to the grammar) and the file of expected documenter output matched.

Jan 31st

I found the problem with parsing the grammar, and I feel very foolish about it!

I put a breakpoint in Parser.java at the top of the method public void addRule(String input) and put a watch on the value of input. I ran the JUnit test and watched as the value of input changed to each of the rules described in the grammar files. It turns out that even though the umple_patterns.grammar file (when I ran the test) contained the rule:

softwarePattern- : [[isA]] | [[singleton]] | [[immutable]] | [[keyDefinition]] | [[codeInjection]]

the value of input at the breakpoint was

softwarePattern- : [[isA]] | [[singleton]] | [[keyDefinition]] | [[codeInjection]]

Clearly my changes to the grammar files were not translating into changes in the behaviour of the Umple compiler! I ran ant -Dmyenv=local -f build.umple.xml umpleSelf compile and found that now the rule showed the changes I expected to see.

In short, it appears that I was making changes to the grammar and expecting the tests to pass even though the grammar changes hadn't been built into the Umple jar. I'm not sure how I got into this pattern, or why I would have thought that the changes to the grammar files on the file system would effect changes to the parser behaviour, but I've learned my lesson. On the plus side I've spent enough time browsing through the parser code to have a better understanding of what's going on underneath the parser's hood. Now assertParse() is succeeding in the JUnit test. Now the test is failing at:

Assert.assertEquals(true,model.getUmpleClass("Student").isImmutable());

I must gain a better understanding of how the compiler is building the classes such that properties relating to immutability are being correctly set.

Jan 27th

I'm attempting to determine why umple_patterns.grammar is not getting parsed the way I expect it to. (immutable keyword is getting parsed as an attribute instead of a software pattern.)

I have tried adding a grammar rule for immutable so its precedence in the classContent rule (in umple_classes.grammar, in cruise.umple.src) is before the attribute rule. For some reason, the rule for the immutable keyword seems to get bypassed, since in my test class the line

immutable;

is always getting interpreted as a String attribute named "immutable". Ultimately I want the rule for immutable to be located in umple_patterns.grammar where the singleton and isA rules are defined, but since those grammar rules lower in the parsing precedence, I've been trying this alternative approach in an attempt to determine why the immutable keyword isn't getting parsed as expected. I will have to think up a different tack since the rule seems not to be recognized no matter how high in precedence I place it.

On the bright side, I was able to solve the problem with my desktop development environment, so now I have the option to work on that machine instead. (I simply deleted the umple project from my machine and checked out a clean copy, and it built successfully.)

Jan 26th

Tested UmpleOnline using IE9 on Windows 7, and using Firefox on Windows 7 and Ubuntu. Findings posted to umple-dev mailing list.

Jan 23rd

I simply spent some time at home trying to iron out the problems with my desktop development environment using the approaches discovered during the UCOSP code sprint when setting up the environment on my laptop. Barriers were encountered. Building on the command line produces 14 errors of type "duplicate class" like the following:

[javac] /home/sonya/umple/umple-read-only/cruise.umple/src-gen-umple/cruise/umple/compiler/Couple.java:7: error: duplicate class: cruise.umple.compiler.Couple
[javac] public class Couple
[javac]        ^

I executed an svn update, and reverted all changes that might have inadvertently made to my local copy of the project, and found that doing those things didn't change the outcome of the build.

When building in eclipse, the following errors show up:

Description	Resource	Path	Location	Type
OptionParser cannot be resolved to a type	UmpleConsoleMain.java	/cruise.umple/src-gen-umple/cruise/umple	line 39	Java Problem
OptionParser cannot be resolved to a type	UmpleConsoleMain.java	/cruise.umple/src-gen-umple/cruise/umple	line 39	Java Problem
The import joptsimple cannot be resolved	UmpleConsoleMain.java	/cruise.umple/src-gen-umple/cruise/umple	line 7	Java Problem

Refreshing the project doesn't do anything to improve matters.

For the time being, I will continue to program on my laptop and try to proceed on the work I began during the UCOSP sprint. I will leave the build errors on my desktop alone for the time being, though I will eventually have to sort them out since it will be easiest for me to work on my desktop as compared to my laptop in the long run.

(I also took time to re-order my logs in reverse chronological order so it's easier for readers and myself to quickly find the most recent entries rather than scrolling all the way down the page.)

UCOSP Code Sprint - Jan 20th-22nd

Jan 22nd

Began work on the UmpleTo* projects, to ensure that the parser is now able to parse Umple code that contains use of immutable at the class level.

  • When those projects were added to eclipse, built and attempted to be run, more cases of the previous version of the Attribute constructor were found. Much search-and-replace was done was to fix test cases in those projects to use the new constructor that was required as a result of the 1 -- * bi-directional association between UmpleClass and Attribute classes.
  • Test cases were written both for the parser and for the internal parser. The cases currently fail, however, because the expected changes to the grammar didn't produce the desired results. Andrew wasn't able to figure out why this was either. We had to leave off figuring this out for the time being, and hopefully can make some progress in our respective cities.

Jan 21st

Began work on issue 241, immutability at the class level. With assistance from Andrew, began to understand the process of how Umple is built from Umple. Steps taken thus far:

  • created test for, ant then created, externally-accessible isImmutable() method for UmpleVariable. This is so that the JET interface has a clean way to determine if an attribute is immutable (regardless of whether the attribute itself is individually immutable or if the entire class is immutable).
  • created test for, and then created, immutable property and isImmutable() method for UmpleClass.
  • to Attribute class, added (and created test for) isImmutable() method that checks both property UmpleVariable property and property of associated UmpleClass to make a determination.
  • required making relationship between UmpleClass and Attribute bi-directional because previously Attribute did not require knowledge of UmpleClass it belongs to (changed 1 -> * Attribute to 1 -- * Attribute). Required refactoring code because now the associated class must be provided to constructor whenever an Attribute is created.

Jan 20th:

I spent the day ironing out development environment setup. Issues I encountered:

  • I did not have the ant-contrib in my ant directory, causing build problems.
  • required installation of php, php-cli, and ruby on my machine (realized when ant issues were dealt with and new errors indicated these languages weren't installed yet).
  • due to all the failed builds, required fixing of the UMPLE_VERSION problem (command line: ant -Dmyenv=local -f build.umple.xml -Dumple.version=1.2.0.1236 template.resetVersion, as suggested on this wiki page.)

Jan 15th

I missed the teleconference due to not receiving the message in time. For that reason I've worked from the notes made on the conference, as well as the log entries made by Jordan Johns since he and I have been experiencing identical problems with both the plugin and with test failures. Note: thank you Jordan for your detailed documentation. It has helped me very much.

I reinstalled eclipse and added the umple plugin using Step 2, Method 2 described at http://code.google.com/p/umple/wiki/Install_Eclipse_Plugin. This time the project showed zero errors. The JUnit tests still fail, however, showing 191 errors and 456 failures.

I have a point of comment/confusion, however: I'm not sure how to directly follow this instruction: "Use Umple to generate all .ump source files. If you want to compile Umple itself, you can do this can do this by compiling this file: cruise.umple/src/Master.ump ". In my project menu I have "Build Automatically" checked, so all umple appears to build whenever I select "Clean...". But whenever I attempt to build from a .ump file directly, e.g. I select Master.ump in the package explorer and I click the "Compile Umple" button or click Umple Menu > Compile Umple, I get the error "Please open an Umple file." I must open the file, not just select it, for the build to occur. Also, I see no output anywhere, other than the text "Building Workspace" flashing briefly in the bottom right corner of Eclipse.

Perhaps this is better explained in an Umple tutorial that I've overlooked? I find the lack of output counter-intuitive and a bit mystifying. I attempted to introduce an obvious error into a .ump file and then build to see what would happen, and error X's appeared next to many lines in the file other than the one with the deliberate error, and they wouldn't disappear again until I removed the deliberate error AND closed and reopened the file. The build appeared to not even be attempted as long as the error was present. I will spend some time in the near future trying to educate myself some more on this matter.

Jan 11th

Environment: Ubuntu 11.10 (VM), running commands from Terminal shell.

The conflicting ant versions are the one installed in my computer at /usr/share/ant/lib/ant.jar!/org/apache/tools/ant/Project.class, and inside my umple project directory at umple-read-only/cruise.umple/bin/org/apache/tools/ant/Project.class.

I've so far been unable to find a way around this problem thus far.

Jan 10th

Attempted command-line build as per Tim's suggestion. Results show "Build Successful" but closer inspection shows that ALL of the tests have "FAILED" output. No further information provided with test output to indicate source of failure. Tests are preceded with the following warning:

[junit] WARNING: multiple versions of ant detected in path for junit

... followed by lines describing the two locations on my machine (one inside the umple project, and one in my /usr/ directory) where ant is located. Could this be causing the failures? No other indication of the source of the problem is given.

Jan 8th (2)

Checked out umple source. Problems building project. Similar to James, I attempted to build Master.ump and received message: "Syntax error: Line 13 char 9".

Also similar to James, my project lists multiple "problems":

Errors include:

Bundle 'org.eclipse.xtext.ui.codetemplates.ui' cannot be resolved MANIFEST.MF /cruise.umple.xtext.ui/META-INF line 16 Plug-in Problem

Project 'cruise.umple.xtext' is missing required source folder: 'xtend-gen' cruise.umple.xtext Build path Build Path Problem

And warning:

xtend-gen/ is missing from source.. build.properties /cruise.umple.xtext line 3 Plug-in Problem

In addition, other errors/warnings related to projects that could not build because xtext is not building.

I followed James's lead and created the empty xtend-gen folder to eliminate that error. Resulting errors appeared of type "cannot be resolved," mostly relating to the package org.eclipse.xtext.ui.codetemplates.

Note: warning indicates that I haven't got the correct jre installed for execution environment j2se-1.5. I will deal with this error first.

Jan 8th

Term has had a sluggish start due to personal matters and large amount of start-up readings required in other classes. Hoping to get up to speed of other UCOSP students before long.

Umple time in past few days has been spent reading through examples at UmpleOnline, including more detailed examples of state machines, making edits in the code/uml editors, and inspecting the details of Java and Php code generated. Only (minor) problem encountered: accidentally entered semicolon rather than colon when adding attribute in uml editor. Code in code editor disappeared and would not reappear when the error was corrected. Required me to start that example over again.

Setting up development environment has been inhibited by more basic, non-umple concerns. My previous ubuntu VM was having issues with security updates, which I chose to circumvent by creating a new VM with most recent Ubuntu distro for purposes of Umple development. This attempt is now on its second try. (Newest distro seems to use a lot more disk space than earlier ones, which didn't become clear to me until after installing eclipse on first new VM and I realized remaining amount of disk space was unsatisfactory.)

Will log update when umple development environment is set up or if problems are encountered along the way.