[Cuis] A few proposed is: additions

Phil (list) pbpublist at gmail.com
Wed Jun 13 12:55:04 CDT 2012


Juan,

On Jun 13, 2012, at 12:28 PM, Juan Vuletich wrote:

> Hi Phil,
> 
> Phil (list) wrote:
>> Juan,
>> 
>> On Jun 12, 2012, at 7:30 AM, Juan Vuletich wrote:
>> 
>>  
>>>> Good point re: the performance concern.  I hadn't thought about that but will keep it in mind as it could potentially be an issue for something that might get called very frequently like is: #Character.  I wasn't clear if the plan was to completely do away with is* in favor of is: or not so your clarification helps.  So my followup question becomes: for something that is likely to be frequently called like #isCharacter that has previously been removed would you prefer to add it back in or replace it with is:?        
>>> It just depends on what you need. What do you need it for? (if you don't then just don't add it).
>>>    
>> 
>> Several of the packages I've ported used the old is* methods for type checking which I've either had to remove or replace with brittle class checks for now. 
> 
> Oh, I hadn't thought about this. Apologies. I think that it makes a lot of sense to add those is* methods in an optional package for compatibility. When adapting a package for Cuis, if all the problems are like this, it is easier to load the compatibility package and do not fork the package you're working on. That would save a lot of code duplication. Something else that could go in that compatibility package is a SmalltalkImage class, whose single class message #current just answers Smalltalk. Same for SystemNavigation current, and any other such idioms that are absent in Cuis.

No reason you should have since compatibility isn't your primary concern (keep things small and dealing with breakage like this from time to time isn't a big deal for me :-)  I think the compatibility package sounds reasonable, so the only question becomes should it become part of something that already exists (i.e. the pharo-compat package or an equivalent squeak-compat (seems like the potential for conflict here would be high since pharo and squeak have their own issues re: compat)) or a stand alone thing.  Agreed re: not wanting to fork the package itself over trivial stuff like this (though for some packages it's necessary as they depend on too much cruft for my taste)

> 
>> In addition, much of the code I'm writing would benefit from them as well.  There are two main situations that come to mind: the first being in-image behavior checking/documentation where type doesn't matter and the second is crossing the image boundary (FFI, emitting text/data files of a specific spec, etc.) where type is everything.  In both scenarios,  the intention is to have errors occur closer to the true source of the problem or ideally preventing the problem from occurring in the first place by noticing that a setter is performing an inbound check.  The second case being more useful when working with code written by someone else.
>> 
>> For example, some of the text/data processing I'm doing will result in the debugger effectively popping up in the middle of nowhere from a code standpoint because it really needed some kind of a date but was passed a string (or some other object behavior mismatch) at some point well before the code actually failed rather than when it finally needed that date behavior.  Iterating over a number is another fun scenario... tracing back to how that number got there isn't always easy as it may have been 25 steps ago in the 10th data file read etc.  Sometimes this is the result of bad data, sometimes it's me simply forgetting to parse/convert good data.
>>  
> 
> I see. In any case keep in mind that #is* and #is: are not type checking, but more something like protocol conformance... In any case they don't give any guarantees at all. Anybody could implement them in any way...

Understood, and I know there are no promises involved.

> 
>>>> Also, for cases where is: does make sense, have you considered rather than hard coding them, backing them up with a collection so that something along the lines of Smalltalk allProtocols could be implemented or is that also a performance concern?
>>>>       
>>> I never thought about that. Do you have an use case in mind? (I usually avoid implementing stuff until I have a good reason. Having a use case usually helps doing a better implementation).
>>> 
>>>    
>> 
>> I have two in mind:
>> 
>> 1) When thinking about overriding is:, it would be useful to be able to look at the other protocols defined to remain consistent where it makes sense (both in terms of defining a new protocol or re-using one that already exists).  Currently you'd have to browse all implementers of is: to do so.  Not a big deal when the number of is: overrides is small, but it becomes unwieldy fast.
>> 
>> 2) When code breaks and you land in the debugger, it would be nice to have a quick way to answer the question 'what is this object it's having a problem with?' in a more abstract sense than what is its class.  Same issue re: browsing implementers of is: as there may be more than one override in the class hierarchy (i.e. if #Number were defined at the top of the hierarchy and #Float were defined further down in the case of numbers.).  This, matched with appropriate is: checks would make troubleshooting some problems much simpler.  Obviously, more classes need to override is: before this use case could be realized.
>> I guess how I'd envisioned it working is: would just become the test method and would call a class side protocols method that would actually return the collection of protocols that a given class supports.  Then in the debugger/workspace you'd call foo class protocols.
>>  
> 
> The problem is that to access the whole collection, including those from superclasses, you need to create collections on each call. This is too expensive.

Sorry I wasn't explicit: I was assuming that there would be a cvar that got lazy loaded (including the walk up the hierarchy) by #protocols on the first call. From the second call on, the performance difference would just be a check for membership in the collection vs. the existing conditional logic approach.  A further assumption was that the class initialization logic would set the cvar to nil to ensure that there was a way to force its regeneration.

If you don't like the idea of creating per-override cvars, a centralized protocol dictionary (i.e. for classes with #is: overrides, the lookup would be performed and if it doesn't exist, populate it with what was returned from #protocols.) could be used instead.

A third approach could be to leave #is: alone and keep the introspection capabilities separate from the test, but then protocol information exists in at least two places: in the current #is: logic as well as the collection-backed store (whether via individual #protocols or a centralized store)

I think a fair question to ask is: does anyone else see value in what I'm proposing or is this something only I want?

> 
>> If there's a better way to accomplish either what I'm looking for in my first answer or what I'm proposing here I'm open to it, this is just what I've come up with (likely without considering other valid scenarios or issues).
>> 
>> ...
> 
> Let's think of a better one, one that is fast and non- redundant.
> 

I definitely appreciate those desires and concur.

> Cheers,
> Juan Vuletich


Thanks,
Phil



More information about the Cuis mailing list