Joel Solon · Feb 17, 2016 go to post

Small comment: use $this instead of ##this, even though they compile to the same thing.

Joel Solon · Feb 22, 2016 go to post

Also note that Caché developers will be able to choose to use Atelier even if the Caché server is not yet on v2016.2 or a later version. Steps:

  • Use a local installation of v2016.2 integrated with their chosen source control system to edit classes and routines.
  • Use Atelier’s export feature to export the file(s) to our standard XML format, and import those files on the Caché server.

Each developer can choose between familiarity with Studio and easy integration with the server (with perhaps no integration with source control), or familiarity with Eclipse and easy integration with source control (with an extra step or two to integrate with the Caché server).

Joel Solon · Apr 8, 2016 go to post

Server Explorer exists on the Mac and was open. I had only used it to explore the contents of the server. But it also allows editing and deleting of the server connection itself. Thanks!

Joel Solon · Apr 8, 2016 go to post

Spoke too soon. Trying to delete or edit a broken connection fails. I am reporting this.

Joel Solon · May 2, 2016 go to post

I never updated this post with the workaround, sorry! The problem is with Secure Storage. You can reset it by going into Atelier > Preferences > General > Security > Secure Storage. Click the Contents tab. Under com.intersys.eclipse.connmgr, you'll see an entry for the connection to the Caché server. Delete that entry, and you should be able to recreate the server connection.

Joel Solon · Jun 6, 2016 go to post

This is interesting stuff and it's good to revisit this as ObjectScript evolves. In the old days, there was advice about things like this:

  • set a=1, b=1, c=1 was faster than set (a, b, c) =1
  • if a]"" was faster than if a'=""
  • etc.

But we always reminded people that these things could change from platform to platform, and that extra database references were usually much costlier than the differences between coding things one way vs another.

So, Tim, if you've got the time, please tell the Community if your tests show different values on Windows vs Linux vs Unix vs OS X. And (this might be harder), give us your opinion on a "tipping point" or a "when to care about this point"; that is, if the delimited or list string has fewer than N pieces/items, it really doesn't matter which method is used, but above N, use the $listlength method, and above M, use $listnext. Something like that.

Joel Solon · Aug 4, 2016 go to post

Very good article that really shows the benefits of $sequence. Do you have an explanation for why the calls to LastName() and FirstName() went from 16.8 sec (using $increment) down to 8.2 sec (using $sequence)?

Also, there's a typo: "acquisitoin" should be "acquisition".

Joel Solon · Aug 4, 2016 go to post

The default behavior for %Save() in Caché classes is still to use $Increment, which will be fine for many cases. $Sequence is intended for cases where the volume and speed of inserts is very very high.

Joel Solon · Aug 4, 2016 go to post

If your class inherits properties from another class, substitute %compiledclass for %class in the solution above.

Joel Solon · Sep 1, 2016 go to post

Usually the variable subscripts in a global will have a name of some kind, known to the developers that wrote or support the application. The name may also be known to the users of the application. I recommend using that name for the property, such as "EmpID" or "EmployeeID" rather than something generic like "Sub2".

Joel Solon · Sep 6, 2016 go to post

Another variation is where the USA.Person class is marked Abstract (so there are no objects/rows that are only Persons). For Kyle's Option #1, we'll make USA.President, USA.Senator, and USA.Representative subclasses of USA.Person. All the politicians will be stored together in the ^USA.PersonD global, with each type marked using the "~USA.President~"-style syntax. Without the bitmap extent index, finding all Senators requires looking through the entire global. With it, there is a bitmap index for each type of politician. Note that this variation provides 4 tables: Person (showing the common data for all politicians), and President, Senator, Representative (showing all the data for each type, including the Person data).

For Kyle's Option #2, the subclasses inherit from %Persistent and USA.Person, and each type of politician is stored separately from the other types. When doing this, you would normally specify [NoExtent] for the USA.Person class. There won't be a Person table in this case.

Joel Solon · Sep 6, 2016 go to post

In the process of writing this article, I discovered that our documentation on these two keywords contains the following sentence: "When you compile this class alone, the compiler does not cause the other classes to be compiled." 

That sentence is incorrect. The documentation has now been fixed, and the updated information will be available online when we refresh the online content.

Joel Solon · Sep 9, 2016 go to post

I thought IKnow required a special license. Can I really do all of this with my regular old Caché license?

Joel Solon · Oct 14, 2016 go to post

Option #1 is "store all persons together in the same global." So, people that are just regular persons, as well as presidents, senators, and representatives, are all stored together, with a single shared ID sequence. Optionally adding [Abstract] to the Person class prevents persons from being created/stored; there will be only presidents, senators, and representatives. With or without [Abstract], adding the bitmap extent index allows quick retrieval of different types of persons.

Option #2 is "store different types of persons in separate globals." Kyle's original description of how to do this is correct. Similar to using [Abstract] for option #1, optionally adding [NoExtent] for this option prevents persons from being stored. So the global structure you show in your first question is correct. Omitting [NoExtent] doesn't change that. You don't have to also use [Abstract] for option #2, but you can.

Joel Solon · Mar 29, 2017 go to post

One clarification that might help you: the "Ensemble Controller" Service is not an Ensemble process, so the user assigned to that Service doesn't affect what you're asking about. The "Caché/Ensemble Controller" Service is simply something that allows you to start/stop the local Caché or Ensemble. It's just like start/stop on the Launcher (the cube or the E).

Joel Solon · Mar 29, 2017 go to post

Regarding the user for Caché/Ensemble processes, the user for those is not always the user that starts/stops Caché/Ensemble. My instance of Ensemble runs on the Mac. For several years, I do a custom install so that I can change the answer to the 4th question below from cacheusr to joelsolon.

User who owns instance: joelsolon
Group allowed to start and stop instance: staff
Effective group for Ensemble processes: cacheusr
Effective user for Ensemble SuperServer: joelsolon

All the Ensemble processes run as OS user joelsolon because of this.

I don't actually have an answer to your question, but maybe these points will help.

Joel Solon · Apr 15, 2017 go to post

I haven't seen this crash at all. Is it possible to share more details about the crash? Error message, for example. Also, if the last edited routine is locked, that doesn't require a restart of Caché. You can find the entry for the routine in the Lock Table (in System Operations) and delete it.

Joel Solon · Nov 1, 2017 go to post

No. I have a feeling that some versions of M that ran on VMS added the $, and some versions of M that ran on UNIX added the !. So we support both.

Joel Solon · Nov 1, 2017 go to post

Setting Startup Namespace in the User definition affects Terminal logins. The feature was expanded to affect the Portal in v2014.1

Joel Solon · Nov 3, 2017 go to post

Slightly improved syntax would be something like this:

if ($zdh(date1,8)<$zdh(value,8)) && ($zdh(value,8)<$zdh(date2,8)) { return 1 } 
else { return 0 }

Joel Solon · Jan 31, 2018 go to post

The legacy versions of If and For commands don't use curly braces. But there are no legacy versions of While and Do/While, which require curly braces. So rather than trying to remember which commands use or don't use curly braces, just use curly braces all the time for these, as well as Try/Catch.

Regarding post-conditionals, it's a good habit to put parentheses around the condition, which allows you to put spaces in the condition.

This is valid syntax: set:a=4 y=10

This is valid syntax and more readable: set:(a = 4) y = 10

This is invalid syntax: set:a = 4 y = 10

Joel Solon · Jan 31, 2018 go to post

C'mon, let's stop mentioning old features like argumentless Do and legacy ELSE

There's just no point in doing so.

Joel Solon · Jan 31, 2018 go to post

Danny and Robert, of course I understand what you are saying (we are the same generation!). Also, I am not trying to be the Developer Community police.

In posts that are asking "what's the recommended way to do this?" we should answer that question. There's no point in mentioning old syntax in that context. Saying "don't do this, but you might see it someday" helps the subset of people that might work with old code, but doesn't help and may confuse the people that are working with new code. It doesn't belong.

On the other hand, if there's a post asking "what are some older/confusing syntaxes I might encounter when working with M or ObjectScript?" we should answer that question. We all have examples of that.

Joel Solon · Jan 31, 2018 go to post

I would do it this way to avoid Else:

Open <some device>:"R":0 If '$test { Write "could not open device" Quit }

Joel Solon · Feb 5, 2018 go to post

Both running VMs and containers allow multiple processes inside. I'm not asking you for a deep dive, but can you explain if the mechanism that allows this is the same or similar between VMs and containers, or if they use completely different mechanisms.

Joel Solon · Aug 23, 2018 go to post

This is nice. The only thing I'm wondering about is why there are #dim statements for regular variables? @Timur Safin, why did you include the #dim statements? In my opinion, #dim statements for variables that are not object references are misleading:

  1. #dim gives developers that are new to ObjectScript the impression that you must declare all variables like in some other languages. Declaring variables like this is not necessary in ObjectScript.
  2. #dim's main purpose is to help Atelier/Studio provide code completion for variables that are object references. If you write this code #dim i as %Integer, and then on the next line you type do i. ,  after the period Atelier/Studio will suggest methods from the %Integer class. If you happen to accept one of the suggestions, the resulting code will not compile. This is because our datatype classes (like %String and %Integer) are not object classes.