Why is SW API so inconsistent and weird?

Programming and macros
laukejas
Posts: 202
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 43
x 114

Why is SW API so inconsistent and weird?

Unread post by laukejas »

This is not a complaint, nor any specific issue, but just something I've been wondering over the years of working with SW API. Although it is very robust and well-documented, there are just so many inconsistent weird things about it that make it really difficult for newcomers to get into it. This applies both to macros and add-ins, and all supported languages. For example:

1. Almost all API calls that return a reference to some API object, return it as a generic Object, rather than a specific class. For example ISldWorks.ActiveDoc returns Object that has to be cast to ModelDoc2 manually. If it's about protecting some proprietary class data, why not return the reference as IModelDoc2, which has nothing exposed?

2. Many API calls that return an array of doubles, return them as a Object/Variant rather than a regular double() array, and then has to be explicitly cast, which is often a nuisance. For example, IModelDocExtension.GetMassProperties2. Even functions that return an array of object references, such as IPartDoc.GetBodies2, return a generic Object that then has to be treated as an array by the user in order to access it's members. Why not return it as a simple Body2 array?

3. Lots of API calls require supplying an ungodly amount of parameters, such as IFeatureManager.FeatureExtrusion2, which requires 23 (!). In almost every scenario, user only needs to control only 1 or 2 of these parameters, while others could be marked as optional and have documented default values. In many cases, there are parameters that are only important in very obscure scenarios. For example, IEntity.Select4 requires supplying an instance of ISelectData, which rarely matters, yet requires lots of additional code to create every time. Meanwhile other functions require passing them an array or object of some type that encapsulates all these parameters, such as IFace2.MaterialPropertyValues (technically a property, not a function, but still), which is a far better coding practice... So why isn't this universal?

4. Continuing on parameters, lots of API calls accept enumerators, especially when supplying types. For example, again the IPartDoc.GetBodies2 requires supplying body type as enumerator from swBodyType_e. Okay... But why the heck do some other functions require supplying types as a String? For example, if you want to select a plane from the FeatureManagerTree, the second parameter of IModelDocExtension.SelectByID2 requires supplying the type (plane) as "PLANE"! Why?? Enumerator exists for it already, it's swSelDATUMPLANES, and it's listed right next to it in the documentation. So why not use that instead?

5. Don't get me started on return value consistency and error handling. Some functions return reference to an object it created/interacted with, for example IFeatureManager.FeatureExtrusion2 returns reference to Feature. But there is no error handling. If it fails, the only way to know it if it's return value is Null. By this logic IModelDocExtension.SelectByID2 should return reference to the object it selected, right? No. It returns Boolean to indicate whether it was successful or not, you need another call (GetSelectedObject6) to get the actual reference. Other calls return Long, which represents an enumerator with error codes, for example ISldWorks.CopyDocument, where 0 = no error, 1 = failure, 2 = another kind of failure, etc. Not to mention that 0 = False in integer/boolean conversion, whereas API calls that return boolean follow convention true = no error, false = error, which is the opposite.

Meanwhile, other functions return their errors through Out / ByRef parameters, such as ISldWorks.OpenDoc6, which requires supplying an empty variable of type Long/swFileLoadError_e for it to write. AND that function also returns True/False to indicate if it opened the doc or not, instead of reference to that doc! Arrrrrrgh!!! Why not just throw a named exception if a function failed, like every other API does??

6. Traversing through features, faces or any other kind of collection is as weird as it gets. For example, you want to get all features in FeatureManagerTree? You'd expect there'd be something like IModelDoc2.GetFeatures, similar logic to IPartDoc.GetBodies2..? Nope. You call IModelDoc2.FirstFeature to get IFeature, and then call IFeature.GetNextFeature to get it's neighbor in a long loop until you get Null to indicate that you got them all. And if you want to get references to all configurations? Yet another logic: first you call IModelDoc2.GetConfigurationNames to get a string array of config names, and then IModelDoc2.GetConfigurationByName, one by one, to get all the references. Just... Why...



I could go on an on, the list of pet peeves with API is endless. Yes, I know that pretty much every issue I mention has a workaround, and you learn them with time, often writing wrappers around SW API calls to hide the ugliness (or use frameworks such as xCAD.NET to achieve the same end), but for people new to SW API, wanting to write macros or simple add-ins, this ungodly mess is often just too much to untangle.

I wonder, how did it come to this? It often feels like the API was made as complex and inconsistent as humanly possible, going against every single best coding practice, every API call working in it's own special way and rules, like every API call was written by a different developer after a 1 week VBA coding crash course.

Again, I'm not looking for any advice or solutions with this post, I'm just genuinely curious what is the historic reason behind this mess :ugeek:
User avatar
JSculley
Posts: 648
Joined: Tue May 04, 2021 7:28 am
Answers: 55
x 9
x 888

Re: Why is SW API so inconsistent and weird?

Unread post by JSculley »

The API is nearly 30 years old. You cannot have backwards compatibility for 30 years without making a mess. Some of the problems are limitations of COM itself (primarily array/variant related weirdness). Some of the problems are due to trying to support 3 (now 4) different programming languages and having to cater to the lowest common denominator (VBA). A large portion of the API is most likely automatically generated, which leads to the multitude of required parameters in some places. There are places where effort has been made to clean it up (e.g. OpenDoc7).

When you are creating an API, you have exactly once chance to get it 100% right. Once it has been released, you are beholden to that design because you have to assume there are users depending on the way it works not changing. Breaking changes are a big no-no.
laukejas
Posts: 202
Joined: Sun Sep 05, 2021 8:27 am
Answers: 0
x 43
x 114

Re: Why is SW API so inconsistent and weird?

Unread post by laukejas »

Well, I had similar ideas, but:
JSculley wrote: Tue Nov 26, 2024 2:31 pm Some of the problems are limitations of COM itself (primarily array/variant related weirdness). Some of the problems are due to trying to support 3 (now 4) different programming languages and having to cater to the lowest common denominator (VBA).
Even VBA supports strong typing, early binding and SW API objects, so I'm not sure what limitations it could be imposing. Perhaps you are right, there are some COM related limitations, although other APIs (for example Excel API) happily return specific objects instead of generic object/variant. Perhaps this was a limitation long time ago that has since been removed in other APIs, but remained in SW?
JSculley wrote: Tue Nov 26, 2024 2:31 pm You cannot have backwards compatibility for 30 years without making a mess.
True, backwards compatibility is a PITA, but SW API seems to be solving this in a very clean way, by versioning each API call/object (OpenDoc3, OpenDoc4, OpenDoc5, etc.), with each version having it's own documentation and so on, meaning these versions are not really dependent on one another. Many times the number of parameters and even return types change between these versions; so why would fixing parameter/output type/usage mess, break anything? The old versions could continue working the same way they did before.
JSculley wrote: Tue Nov 26, 2024 2:31 pm A large portion of the API is most likely automatically generated, which leads to the multitude of required parameters in some places. There are places where effort has been made to clean it up (e.g. OpenDoc7).
This one does seem to be the most plausible explanation... :shock: Please correct me if I'm wrong on the other points
User avatar
Frederick_Law
Posts: 1952
Joined: Mon Mar 08, 2021 1:09 pm
Answers: 8
Location: Toronto
x 1648
x 1477

Re: Why is SW API so inconsistent and weird?

Unread post by Frederick_Law »

1: Activedoc can be part, assembly, drawing etc. Programmer should check what it is before casting to correct object. Of course, programmer could just use VB last casting.
User avatar
JSculley
Posts: 648
Joined: Tue May 04, 2021 7:28 am
Answers: 55
x 9
x 888

Re: Why is SW API so inconsistent and weird?

Unread post by JSculley »

laukejas wrote: Tue Nov 26, 2024 3:59 pm Well, I had similar ideas, but:

Even VBA supports strong typing, early binding and SW API objects, so I'm not sure what limitations it could be imposing. Perhaps you are right, there are some COM related limitations, although other APIs (for example Excel API) happily return specific objects instead of generic object/variant. Perhaps this was a limitation long time ago that has since been removed in other APIs, but remained in SW?
VBA is the lowest common denominator because it lacks things like inheritance, it doesn't have nearly as powerful language features as C++/C#, etc. If SOLIDWORKS were to pick a single language to support, then the API could take advantage of all the stuff that it unique to that language.

COM is language agnostic. A COM server (the SOLIDWORKS application) has no idea what language the COM client is written in. So, the parameters and return values for a COM method call must be something that any calling language can understand. To tailor this to 4 different languages would require creating 4 different APIs to sit in front of COM to translate parameters and return values to the best fit for each language. Sure, it's possible, but SOLIDWORKS isn't going to spend the time/resources to do it. I started the process of developing a Java interface to SOLIDWORKS 20 years ago. Then C# arrived and was good enough that I could hold my nose for the bits that actually had to communicate via the API.
True, backwards compatibility is a PITA, but SW API seems to be solving this in a very clean way, by versioning each API call/object (OpenDoc3, OpenDoc4, OpenDoc5, etc.), with each version having it's own documentation and so on, meaning these versions are not really dependent on one another.
This is actually a requirement of COM. You are not allowed to change the interface of an existing COM object. You have to create a new COM object and incrementing a number at the end is a COM convention. Also, the new interface typically inherits from the old interface, so the new methods are sort of bolted on to the old interface. You can't, for instance, add a new method with the same name as an existing method and the same number of parameters with the same types. COM wouldn't know what to do when the method is called.
Many times the number of parameters and even return types change between these versions; so why would fixing parameter/output type/usage mess, break anything? The old versions could continue working the same way they did before.
Automated tools to generate the API won't know how to 'fix' that sort of thing. It would require humans and it is rare for an API to be given much thought or care.
Post Reply