Wiki Home

Function Sys 2015


Namespace: VFP
Sys(2015) is a handy VFP function which returns a value unique to that session of VFP, unless you call it in a tight loop on a fast machine. The help file says "Calling SYS(2015) more than once during the same millisecond interval returns a unique character string." Tests on a Pentium @ 2.3 GHz have demonstrated that this is no longer the case. With that caveat in mind, it's very handy for generating a unique value for something which is not going to be used outside of that VFP session, such as a name for an object in a collection:

If there was a problem with sequential calls to SYS(2015) producing the same result, they are gone in version 9 sp2 on a MUCH faster processor. -- Ben Creighton

LOCAL I, loMyObject, loCollection
loCollection = CreateObject("Collection")

FOR I = 1 TO 10
  loMyObject = CreateObject("myObject")
  loCollection.Add(m.loMyObject, m.loMyObject.GetUniqueID())
ENDFOR

DEFINE CLASS myObject AS Custom
  PROTECTED cUniqueID
  cUniqueID = Null
  FUNCTION GetUniqueID()
  	IF Vartype(THIS.cUniqueID) != "C"
      THIS.cUniqueID = Sys(2015)
    ENDIF
    RETURN THIS.cUniqueID
  ENDFUNC
ENDDEFINE

FUNCTION RemoveObject(toObject, toCollection)
  * Easy and fast:
  toCollection.Remove(m.toObject.GetUniqueID())
  * Hard and slow (and fails silently if the object isn't in the collection):
  LOCAL I
  FOR I = 1 TO m.toCollection.Count
    IF m.toCollection.Item(m.I) == m.toObject
      m.toCollection.Remove(m.I)
      EXIT
    ENDIF
  ENDFOR
ENDFUNC


The advantage to that approach is that you don't have to iterate over the collection to find the index of the object to remove it, which can have significant performance implications.

This function is also handy for things like temporary file names, though you have to check to make sure the file doesn't already exist, in that case.

Never, never assume that you won't get lucky with this function and generate two of the same "unique" name if you're dealing with two different VFP sessions (multiuser). Inevitably, you won't during testing, and your clients will.


My experience has shown no issues around using SYS(2015) for many purposes including generating Primary Keys as the default value. I have limited this to software running locally on one computer only. Otherwise, I have found using a new GUID function as a wonderful way to generate keys. The only drawback so far is the keys are large and difficult to work with. However, they are unique and easily passed to SQL Server.

FUNCTION GUIDGen
	LPARAMETERS tn_mode

	LOCAL ;
	lc_guid_return as String, ;
	lc_buffer as String, ;
	ln_result as Integer, ;
	lc_GUID as String

	DECLARE Integer CoCreateGuid ;
	   IN ole32.dll ;
	   String@ pguid

	lc_GUID = SPACE(16) && 16 Byte = 128 Bit
	ln_result = CoCreateGuid(@lc_GUID)

	IF tn_mode = 0
	lc_guid_return = lc_GUID
	ELSE
	lc_buffer = SPACE(78)

	DECLARE Integer StringFromGUID2 ;
	    IN ole32.dll ;
	    String  pguid, ;
	    String  @lpszBuffer, ;
	    Integer cbBuffer

	ln_result = StringFromGUID2(lc_GUID,@lc_buffer,LEN(lc_buffer)/2)
	lc_guid_return = STRCONV((LEFT(lc_buffer,(ln_result-1)*2)),6)
	ENDIF


	RETURN lc_guid_return
ENDFUNC



I also have found issues working with SYS(2015), especially on older versions of FoxPro. Here is a simple workaround.

m.UniqueString=UniqueString()

FUNCTION UniqueString
LOCAL m.Result
m.Result=SYS(2015)
DO WHILE m.Result=SYS(2015)
ENDDO
RETURN m.Result


Contributors: Peter Crabtree, Jim Wiggins, Loris Antonangeli (problem on fast machine)
Category VFP Functions
( Topic last updated: 2012.05.26 12:17:44 PM )