The Origins Story

Can someone explain to me how Sensetalk came to be and what the origins of Eggplant Functional were? My team is part of a large IT services company and is heavily invested in Eggplant Functional. For myself, I understand that Sensetalk came from the Next computer (Steve Job’s company formed after he was forced out of Apple) and I have good historical understanding of how Next’s OS and programming environment were Smalltalk based (I’m a Smalltalker myself). I assume that Sensetalk borrowed its design from Smalltalk but was written for business users and testers who would be put off by trying to learn a computing language that looks like this:

exampleWithNumber: x
    | y |
    true & false not & (nil isNil) ifFalse: [self halt].
    y := self size + super size.
    #($a #a 'a' 1 1.0)
        do: [ :each |
            Transcript show: (each class name);
                       show: ' '].
    ^x < y

… so the “syntactic sugar” of Sensetalk was added to make it feasible to get non-programmers coding in it, but these are all assumptions on my part. I love Dan Ingalls and the work that Xerox Parc did and would love to know whether it morphed into Eggplant in the design of this product.

1 Like

NB Wikipedia is a good starting place for Smalltalk, Parc, Dan Ingalls and Next Computer. Not so good for Sensetalk unfortunately, perhaps we could jointly remedy that.

HyperTalk - Wikipedia - looks familiar!

Yes, that’s one of the articles, but why was it done like this is my question, what are the design motivations?


check this webinar out. It will provide you some more details who, how and why sensetalk was developed.

High level story line is to make it more approachable for non developer person and code in a way you would “say” it.


Thanks Karsten, I shall!!

Doug’s cameo appearance there is excellent, he really does do a good job on explaining the “why?” - and he’s very modest about the achievement of curating a programming language since its earliest days. Tell him that I have a Dennis Ritchie mug here, and that more merch is entirely appropriate. Thanks again for sharing, Karsten.

SmallTalk and SenseTalk are different from each other and are unrelated. The only common trait I see between the two is that both platforms are object oriented in nature but still their approach are vastly different. While SenseTalk originated back in the 90’s, it is correct that it initially started from Apple back in the mid 80’s when it was called HyperTalk to allow people to put together code in an English pseudocode manner without having to have a degree in computer science. There are two types of testers in this world. There are those that don’t have any programming experience (and rightfully so since their job is to test) and you have testers that do have an engineering background. SenseTalk caters to both and it has evolved so much over the years for all testers. It is truly an amazing interpreted language to use in an intuitive way. For more information about Keysight’s SenseTalk language, please visit us at About SenseTalk | EPF Docs

Okay - I see four types of users (rather than specifically testers): testers new to programming; testers with SenseTalk expertise; non-testers who are primarily developers but who have been brought into a team to help with scaling and other issues; and finally architects/CTOs who are trying to fix scaling problems with writing SenseTalk code (that’s the class I probably best fit in).

I think the latter two classes are very important, because they show up when the project is mission critical and starts to become a burning platform, and these people have design patterns in their heads that they want to see implemented, specifically around coding to interfaces (what “The C Programming Language” by K&R calls “Function Prototypes” or “Function Declarations”).

Coding to interfaces underpins scaling teams up, because it supports development by separate teams of co-dependent code modules that have clearly defined contracts. SenseTalk seems to be rather weak in this area, insofar as those language features for handling large dev teams are not a priority. Which is fine to a point, but then not good at all. This is something that I’d like to explore – Steve your email explains the “what” of SenseTalk but not the “why”, which is much more fundamental to learning its use and abuse cases, and making sure that everyone plays nicely together?

I only stop by the forum here now and then, so I just came across this (rather interesting!) conversation. I haven’t looked at K&R in many years, but you got me to pull it off my shelf and take another look!

It’s true that SenseTalk, by its fundamental nature, is very flexible and easy-going which is somewhat at odds with your goal of “coding to interfaces” with “clearly defined contracts”. In particular, handlers can declare the parameters that they expect but not their type, and callers are free to pass any number and type of values. Named parameters and default values, which were added to SenseTalk fairly recently, may help a tiny bit. But for the most part right now I think you’ll have to rely on clear communication among your team, probably beginning with naming handlers and parameters well. You might also find EggDoc helpful. And defensive programming within handlers (using assertions, etc.) to ensure things are being called as expected.

Beyond that, I’m curious to know more about your particular concerns and pain points and what language features you think would be helpful. I’ve done some speculating about things that might be added in the future but nothing very concrete, so your input is welcome. But of course for now you need to find the best way to work with what’s already there. So I’m also happy to answer questions when I can - about “origins” or design philosophy if that’s helpful. And if you feel like helping to improve SenseTalk’s representation on Wikipedia that would be great!

Cheers, Doug

I’m definitely up for improving the Wikipedia article. Could we schedule an informal virtual meeting to talk about our pain points Doug? I’d very much want to timebox it and fit around your other commitments, I feel a whiteboard session would put us back on track.
If you’re in agreement, I’ll set up a virtual meeting via an email to you? I want the substantive parts of the conversation to stay in the forum but there’s a balance between distracting the other parties who read the forum and hopefully solving our problem jointly, obviously.

I have been thinking more about why a language gets traction and widespread adoption, and I have come to a conclusion that I’d like to develop in my next post: one important aspect is whether it supports component based design.

I may not be a good Python programmer, but say that I want to generate a 3D barcode for an URL and I don’t want to tie that generated URL to a service provided by a small Internet start-up which will generate the barcode for me, but sneak a link to their web service into every call made when a user scans the barcode with their iPhone.

In Python, I don’t have to code from scratch, I can import a component written by someone else and found on Github into my Python script to do the job:

# Importing library
import qrcode
# Data to be encoded
data = 'QR Code using make() function'
# Encoding data using make() function
img = qrcode.make(data)
# Saving as an image file'MyQRCode1.png')

This gets me my barcode:

Now, that was trivially easy to do - I have extended my versatility by loading a library from a third party into my program and using it.

Compare with SenseTalk - and you see my pain point. What, I have to code this barcode generator function from scratch? No way!

@webbje I’ve only been using Eggplant part-time for about five years. I was all about GNU/Linux back in the 1990s and when I became a software tester full-time in 1999 I started exploring new systems. I became interested in OS X and started playing with GNUstep in the early 2000s, which included SmallTalk scripting under the StepTalk framework. I kept trying to make it do more, however, from the perspective of a system hacker and I never let myself simply let SmallTalk do what it was meant to do.

My great mental leap from code-oriented GNU hacker came when I started learning the 4Test and BDL scripting languages when my company bought Segue tools for testing. I finally learned to approach automated testing from the perspective of “testing” rather than “development”. As a system hacker I appreciate the pain you express in your example. Yet I have to say, even though I’m now doing more work with Helper Suites in much the same way a Perl or Python programmer might approach developing a module, I don’t see it the same way at all. Just the same way I stopped trying to treat 4Test and BDL as C or Perl, I’ve stopped looking at SenseTalk as a “language” in the context of programming.

I’m assuming your QR code example isn’t mean to specifically target QR code creation and rather reflect a model that exists within the context of high-level, general-purpose programming languages. The main difference I see is that Eggplant with SenseTalk is meant to allow the tester (whom we assume has little to no coding experience) to accomplish the creation of a test framework that is tailored to the needs of their specific SUT. I’ve come to the realization that Eggplant with SenseTalk, while there is surely refinement and additional features that would improve upon the application, does exactly what it sets out to do and provides what I need to create stable function libraries while maintaining scripts that are constantly changing as our SUT changes. I don’t see SenseTalk as a “general-purpose” programming language.

Again, I do appreciate your example but the main difference I see is that on the one hand, developing a module in Python or Perl usually provides some feature that is rooted in a standard model, such as TCP/IP, DB or Math. Considering the potentially millions of different SUT out there, it only makes sense for the Eggplant user to create their own module-like frameworks tailored to their needs by hand and leverage those in their scripts. Now, if there were features to be added to Eggplant that were based upon standard models that SenseTalk doesn’t currently allow calls to, I’d see that as a great opportunity for a feature request. I guess the question is, what would those be?

1 Like

@webbje I agree that it would be nice to have a way for people to develop, share, and use components in SenseTalk as you’ve suggested. It’s definitely an area worthy of more exploration. I’m also curious if you have an answer for @chrisbryant ’s question — are there particular components or capabilities that you’re looking for right now? There may be ways to satisfy some of those needs now, even if they’re not as elegant of solutions as one would hope.

I’ve been on vacation for a week and I’m delighted to see @chrisbryant respond so thoughtfully; there’s a lot of wisdom in your reply Chris! To an extent I’m mollified by the message in there, which is that it is unhelpful to see SenseTalk first and foremost as a programming language, and that the effective user will see it almost as an abstraction of the behaviour we want to exercise in the system under test. This helps, because a well-written SenseTalk script will explain what is being tested and how the test is conducted.

I’m groping towards restating my mental model of what we want and I’m under a little time pressure today but I wanted to respond while your replies were still fresh. The key point that I want to get across is that Github has millions of lines of code available for re-use that the budding writer can plug into their existing code base without needing to understand the implementation of the functions they’re using, they just need to understand how the API provided by the bundle is used and what pre-conditions and post-conditions apply when they use the bundle(s) they download. If Sensetalk had this feature, I’d argue that despite the complexity of the various SUTs that we test, common libraries and design patterns would spontaneously emerge that would leverage the work that enterprises have already invested in test software. We’re all missing out on a significant opportunity for code re-use because three or four prerequisites for it don’t exist yet.

Here’s my most high level generic model of what I want from a test, which I can talk around to flesh out the argument I’m making:

This is freely borrowed from the xUnit test frameworks with a bit of the Cucumber way of specificying a test in the middle, in “business user speak”. I’m not going to talk more about Cucumber because it is a distraction at this point, but it does provide a generalised way of specifying a user story in terms of test steps. More on Cucumber at Wikipedia and elsewhere.

Note that the “Begin Test Fixture” code maps well into SenseTalk’s support for loading data from Excel files, and setting up the file system of the SUT with state that the test needs to have available, or doing a miriad of other steps required to have a repeatable test. There are many ways of setting up state outside of reading variables from Excel, but that’s a classic example of SenseTalk makes a hard thing easy to do.

Now in our testing of a large medical case management system, we have refactored Begin Test Fixture code out into separate scripts that define functions that can be called to set the fixture up, and this should be a great place for common code to be shared between teams working on different flows through the system that all need to set up the same preconditions - for example, to make an appointment for a doctor to see a patient requires the same steps irrespective of whether the doctor is a General Practioner or a Dentist; the flows once into the test cases are wildly different but both flows need a new test patient to be registered. I’ll come back to this common code in a moment but bear in mind that “register a patient” and “create an appointment” are both candidates for being common libraries, and they exercise about 5% of the functionality of the system jointly. You can imagine that we might have 40 developers spread across a large number of pizza-sized teams that all want to work without copying and pasting code from one another - they want to use functions that abstract and encapsulate the test setup stage of the test out of the way so that it doesn’t block their progress on the unique steps of the test they are writing.

The next step is the “AS A …” where we plug in a user role as a variable; the user role makes the system perform some steps differently (a dentist usually wants to see dental charts, unlike a General Practioner). So variables are very important as parameters that can facilitate re-use.

I think we all understand how the GIVEN… WHEN… THEN… steps are coded in SenseTalk using standard control structures - we don’t have any issues with how SenseTalk supports these, and we particularly like the exception block structure for handling situations that can arise, but which are exceptional in terms of the normal flow of the test. We understand how to use logError and logSuccess to report the test step outcome using an assertion and we use those rigorously (we think).

Next we get into the End of test fixture code, which again is common (as the Begin Test Fixture code is) to many different scenarios. In our case, we may want to remove the registered patient from system here, after saving any test data artifacts that are significant and that come from running the test.

As we progressed with our code refactoring, we made more and more use of generic handlers or snippets for wrapping up processing steps into calls to common code functions; here’s a basic example that will probably be very familiar to you, although the specifics may vary between Keysight customers:

to ClickEvent MyObject,expOutCome, waitTime:mediumWait
	if file (suiteinfo().imagesFolder&"/"&MyObject) exists or if file (suiteinfo().imagesFolder&"/"&MyObject&".png") exists then
		Click {image:MyObject,waitfor:waitTime}
		Click {text:MyObject,waitfor:waitTime, IgnoreNewlines:"Yes", IgnoreSpaces:"Yes", TrimWhitespace:"Yes"}
	end if
	if expOutCome is not empty then
		if file (suiteinfo().imagesFolder&"/"&expOutCome) exists or if file (suiteinfo().imagesFolder&"/"&expOutCome&".png") exists then
			waitFor waitTime, {image:expOutCome}
			waitFor waitTime, {text:expOutCome,waitfor:waitTime, IgnoreNewlines:"Yes", IgnoreSpaces:"Yes", TrimWhitespace:"Yes"}		
		end if
	end if
	//CaptureScreen increment:yes
end ClickEvent

The challenging part of all of this is that we want to present common code (and its dependent images and other resource files) as components to be consumed as black box entities by teams, rather than through them copying and pasting from scripts that we provide. This means specifically that common code will need its own namespace to distinguish code from one provider from code from another (so that this particular ClickEvent function can be distinguised from another function with the same name from a different provider), and also import statements to identify which library is being used to provide the function, to disambiguate it. It also requires the ability I mentioned in a previous post of defining a method signature for a function separately from the implemention of the method (coding to interfaces); because without this, one can’t abstract the implementation of a function away from the interface or API that is used to make a call to it - you can’t achieve plug-and-play component based development.

That’s about as much as I can sensibly write in a single post response - hope you can see what I’m outlining and I very much look forward to your comments on it, folks :grinning: