[Math] If and only if (IFF) in programming

This is a highly popular and important construct in mathematics. Denoted by two-sided arrow: P <=> Q. As they say, this is a 'biconditional' relation, meaning that if P, then Q, but also vice versa: if Q, then P.

There is also another meaning: if P then Q, but there are no other conditions other than P, that can lead to Q.

'If and only if' is often abbreviated as IFF. Some people unaccustomed to mathematical books may think that IFF is a typo (the author of these lines has also experienced this in past).

I grep'ped some books and source codes with 'if and only if'. Let's see what I've found.

Debug messages

/*
 * Log a message to stderr if and only if "verbose" is non-zero.
 * This uses the err(3) functionality.
 */
void
logx(const char *fmt, ...)
{
	va_list		 ap;

	if (verbose && fmt != NULL) {
		va_start(ap, fmt);
		vwarnx(fmt, ap);
		va_end(ap);
	}
}

( https://github.com/openbsd/src/blob/master/usr.sbin/rpki-client/main.c )

Here is IFF used to show that a debug message will be printed IFF corresponding debug flags are set. There is no other condition that can lead to this. In other words, if you see a debug message, some debug flag is set. Unless your code or the CPU is buggy, there is no other way to allow this to happen.

/*
 * Master debug print macros
 * Print message if and only if:
 *    1) Debug print for the current component is enabled
 *    2) Debug error level or trace level for the print statement is enabled

( https://github.com/torvalds/linux/blob/master/include/acpi/acoutput.h#L265 )

Return value

Here is how IFF is used when describing return code.

This usually means, that if a function returns X, there is only one single condition that can lead to it.

/* Return 1 if and only if the PWM interface is safe to use */

( https://github.com/torvalds/linux/blob/master/drivers/hwmon/it87.c#L2978 )

 * Returns true if and only if the previous command state was equal to 'old'.

( https://github.com/torvalds/linux/blob/master/drivers/infiniband/ulp/srpt/ib_srpt.c#L797 )

/*
 * shm_may_destroy - identifies whether shm segment should be destroyed now
 *
 * Returns true if and only if there are no active users of the segment and
 * one of the following is true:
 *
 * 1) shmctl(id, IPC_RMID, NULL) was called for this shp
 *
 * 2) sysctl kernel.shm_rmid_forced is set to 1.
 */

( https://github.com/torvalds/linux/blob/master/ipc/shm.c#L342 )

-ENOENT will be returned if and only if no GPIO has been assigned to the device/function/index triplet, other error codes are used for cases where a GPIO has been assigned but an error occurred while trying to acquire it.

( https://github.com/torvalds/linux/blob/master/Documentation/driver-api/gpio/consumer.rst#obtaining-and-disposing-gpios )

read-only: legacy interface that indicated whether a memory block was likely to be offlineable or not. Nowadays, the kernel return 1 if and only if it supports memory offlining.

( https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/mm/memory-hotplug.rst#memory-block-configuration-via-sysfs )

NAME
feof — test end-of-file indicator on a stream

...

RETURN VALUE
The feof() function shall return non-zero if and only if the end-of-file indicator is set for stream.

( POSIX 2017 )

NAME
ferror — test error indicator on a stream

...

RETURN VALUE
The ferror() function shall return non-zero if and only if the error indicator is set for stream.

( POSIX 2017 )

Features supported

Sometimes, IFF is used to stress the fact that some feature must/shall be enabled only IFF corresponding hardware is present. Or a compiler/OS/API can support this feature.

Standard input and standard output are fully buffered, if and only if they do not refer to an interactive device.

( W. Richard Stevens, Stephen A. Rago - Advanced Programming in the UNIX Environment )

10.3.1 Enumeration and Enabling

System software enables SMAP by setting the SMAP flag in control register CR4 (bit 21).
Processor support for SMAP is enumerated by the CPUID instruction. Specifically, the processor supports SMAP
only if CPUID.(EAX=07H,ECX=0H):EBX.SMAP[bit 20] = 1.
A processor will allow CR4.SMAP to be set only if SMAP is enumerated by CPUID as described above. CR4.SMAP
may be set if paging is disabled (if CR0.PG = 0), but it has no effect on processor operation in that case.
In addition, two new instructions: CLAC and STAC (see Section 10.6) are supported if and only if SMAP is enumer-
ated by CPUID as described above.

( Intel® Architecture Instruction Set Extensions Programming Reference, December 2013 )

  ATM_LAYER_STATUS in the control register distinguishes between the
  two possible physical layers (25 and 155). It is not clear whether
  the 155 cards can also operate at 25Mbps. We rely on the fact that a
  card operates at 155 if and only if it has the newer Horizon Ultra
  ASIC.

( https://github.com/torvalds/linux/blob/master/drivers/atm/horizon.c#L108 )

	 * Skip the write to HW if and only if the device is currently
	 * suspended.

( https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c#L302 )

/* make sure fw funcs are set if and only if we have fw*/

( https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/i915/intel_uncore.c#L2176 )

	/* Check whether PTP is implemented on this NIC.  The DISABLE
	 * operation will succeed if and only if it is implemented.
	 */

( https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/sfc/ptp.c#L2188 )

CM_POLL_EXTERNAL_POWER_ONLY:
    poll this battery if and only if an external power source is attached.

CM_POLL_CHARGING_ONLY:
    poll this battery if and only if the battery is being charged.

( https://github.com/torvalds/linux/blob/master/Documentation/power/charger-manager.rst#4-charger-manager-data-struct-charger_desc )

Provide a detect function if and only if a chip can be detected reliably.

( https://github.com/torvalds/linux/blob/master/Documentation/hwmon/submitting-patches.rst#3-new-drivers )

RFCs are abdundant with the IFF idiom:

The T-bit should be set if and only if the router is capable of
calculating separate routes for each IP TOS.  The E-bit should be set if
and only if the attached network belongs to a non-stub area.  The rest
of the Options field should be set to zero.

( https://www.rfc-editor.org/in-notes/rfc1247.txt )

   (1)  Change to the up state if and only if the interface is able
        to send and receive packets.
...
   (2)  Change to the lowerLayerDown state if and only if the
        interface is prevented from entering the up state because of the
        state of one or more of the interfaces beneath it in the
        interface stack.
...
   (3)  Change to the dormant state if and only if the interface is
        found to be operable, but the interface is waiting for other,
        external, events to occur before it can transmit or receive
        packets.

( https://www.rfc-editor.org/in-notes/rfc2233.txt )

NAME
 complex.h - complex arithmetic

...

The macros imaginary and _Imaginary_I shall be defined if and only if the implementation
supports imaginary types.

( POSIX 2017 )

Comparison

IFF is often used to stress the fact that a comparison function will return 'true' only if two objects are equal bit-by-bit.

/**
 * bcmp - returns 0 if and only if the buffers have identical contents.
...
 */
int bcmp(const void *a, const void *b, size_t len)
{
	return memcmp(a, b, len);
}

( https://github.com/torvalds/linux/blob/master/lib/string.c#L789 )

Two symbols are identical if and only if they have the same name (by string=?).

...

Two bytevectors are equal by bytevector=? if and only if they have the same length and same contents."

( R. Kent Dybvig - The Scheme Programming Language )

Sets are equal if and only if their contents are equal

( Wes McKinney - Python for Data Analysis. Data Wrangling with Pandas, NumPy, and IPython )

Ouch, that pain of floating-point number comparison:

This is not a bug in gawk or in the MPFR library. It is easy to forget that the finite
number of bits used to store the value is often just an approximation after proper rounding.
The test for equality succeeds if and only if all bits in the two operands are exactly the
same. Because this is not necessarily true after floating-point computations with a particular
precision and effective rounding mode, a straight test for equality may not work. Instead,
compare the two numbers to see if they are within the desirable delta of each other.

( GNU Awk )

In a binary floating-point format, different
computations that produce the same (mathematical) result may differ in
their least significant bits. For example, 1.31e0 + 1.69e0 should produce
3.00e0. Likewise, 1.50e0 + 1.50e0 should produce 3.00e0. However, if
you were to compare (1.31e0 + 1.69e0) against (1.50e0 + 1.50e0), you
might find out that these sums are not equal to one another. The test for
equality succeeds if and only if all bits (or digits) in the two operands are
exactly the same. Because this is not necessarily true after two different
floating-point computations that should produce the same result, a
straight test for equality may not work.

...

This means that two strings are equal if and only if their lengths are
the same and the corresponding characters in the two strings are exactly the
same.

...

The zero flag is set if and only if AX = BX. This is the only time AX − BX
produces a zero result. Hence, you can use the zero flag to test for equality
or inequality.

( Randall Hyde - THE ART OF ASSEMBLY LANGUAGE )

Equality is easy; the ZF flag is set if and only if operand1 has the same value as operand2
no matter whether the numbers are interpreted as signed or unsigned.

( Richard C. Detmer -- Introduction to 80x86 Assembly Language and Computer Architecture )

The object type may be a blob, representing the contents of a file, or
another tree, representing the contents of a subdirectory.  Since trees
and blobs, like all other objects, are named by the SHA-1 hash of their
contents, two trees have the same SHA-1 name if and only if their
contents (including, recursively, the contents of all subdirectories)
are identical.  This allows Git to quickly determine the differences
between two related tree objects, since it can ignore any entries with
identical object names.

( https://github.com/git/git/blob/master/Documentation/user-manual.txt#L3013 )

Values of complex types are equal if and only if both their real parts are equal
and also their imaginary parts are equal. Any two values of arithmetic types from
different type domains are equal if and only if the results of their conversions to the
(complex) result type determined by the usual arithmetic conversions are equal.

( Programming languages — C, N1570, ISO/IEC 9899:201x (AKA C11) )

Here are the rules for an equals( ) method:
...
It is symmetric: x.equals(y) must be true if and only if y.equals(x) is also true.

( Ian Darwin - Java Cookbook )

Conformance to standards

An implementation of the OpenMP API is compliant if and only if it compiles and
executes all conforming programs according to the syntax and semantics laid out in
Chapters 1, 2, 3 and 4. Appendices A, B, C, D, E and F and sections designated as Notes
(see Section 1.7 on page 18) are for information purposes only and are not part of the
specification.

( OpenMP Application Program Interface )

   -- A system can be said to implement this group if and only if
   -- all objects in this group are implemented.

( https://www.rfc-editor.org/in-notes/rfc1559.html )

Data structure consistency or invariant

When we create a new ListNode, we can specify the nodes before and
after so that the appropriate links can be established. We want it to always
be true that b == a.link if and only if a = b.prev for any two nodes a
and b. To help ensure this invariant, we set self.prev.link = self and
self.link.prev = self unless prev or link respectively are None.

( Donald R. Sheehy -- A First Course on Data Structures in Python )

 * struct srp_fr_pool - pool of fast registration descriptors
 *
 * An entry is available for allocation if and only if it occurs in @free_list.

( https://github.com/torvalds/linux/blob/master/drivers/infiniband/ulp/srp/ib_srp.h#L286 )

A tree is balanced if and only if for every node the heights of its two subtrees differ by at most 1.

( Niklaus Wirth - Algorithms and Data Structures )

Mathematics

Something about git's graphs:

When an update changes a branch (or more in general, a ref) that used to
point at commit A to point at another commit B, it is called a
fast-forward update if and only if B is a descendant of A.

( https://github.com/git/git/blob/master/Documentation/git-push.txt#L509 )

Remember the result of an XOR operation is 1 if and only if the operands are different (look again at the table above).

( The Holy Book of X86 )

The exclusive OR of 2 bits is 0 if and only if both bits are equal, else the result is 1 as the truth table in Table 3.3 shows.

( Paul A. Carter -- PC Assembly Language )

We can test whether a number is prime as follows: n is prime if and only if n is its own smallest divisor.

( Structure and Interpretation of Computer Programs )

A set is represented by a bit string in which bit i is 1 if and only if member i is in the set.

( Beautiful Code: Leading Programmers Explain How They Think )

Another special type of graph is a bipartite graph. A graph G = (V, E)
is bipartite if we can split V into two non-overlapping subsets V1 and V2
such that every edge in G connects an element of V1 with an element of V2 .
That is, no edge connects two nodes from the same part of the division. Or,
alternatively, a graph is bipartite if and only if it is 2-colorable.

( Margaret M. Fleck )

A graph is a tree if and only if it is minimally connected.

( NARSINGH DEO -- Graph Theory with Applications to Engineering & Computer Science )

Tests of Divisibility

To test for 2 : A number is divisible by 2 if and only if the
last digit is even.

...

To test for 5 : A number is divisible by 5 if and only if it
ends in 0 or 5. Otherwise the last digit's excess over 0 or 5
equals the remainder.

To test for 6: Test for divisibility by 2 and 3, the factors
of 6. A number is divisible by 6 if and only if it is an even
number with a digital root divisible by 3.

To test for 8: A number is divisible by 8 if and only if the
number formed by its last three digits is divisible by 8....

To test for 9 : A number is divisible by 9 if and only if it
has a digital root of 9. If not, the digital root equals the re-
mainder. The serial number of the bill has a digital root of 1,
therefore it has a remainder of 1 when divided by 9.

...

To test for 10: A number is divisible by 10 if and only if
it ends in 0. Otherwise the final digit equals the remainder.

( Martin Gardner -- The Unexpected Hanging )

The result of the ~ operator is the bitwise complement of its (promoted) operand (that is,
each bit in the result is set if and only if the corresponding bit in the converted operand is
not set).

( Programming languages — C, N1570, ISO/IEC 9899:201x (AKA C11) )

   An AND list evaluates to TRUE if and only if all of its
   constituent conditions evaluate to TRUE.  The overall condition then
   evaluates to TRUE if and only if at least one of its constituent AND
   lists evaluates to TRUE.

( https://www.rfc-editor.org/rfc/rfc3060 )

My other findings

The Haskell way:

Haskell is a language with lazy evaluation. From a programmer’s point of view that means that the value is evaluated if and only if it is really needed.

( https://hub.packtpub.com/getting-started-haskell/ )

Mathematical writing:

On the other hand, punctuation should always be strictly logical with respect to
parentheses and brackets. Put a period inside parentheses if and only if the sentence
ending with that period is entirely within the parentheses. The punctuation within
parentheses should be correct, independently of the outside context, and the punctu-
ation outside the parentheses should be correct if the parenthesized statement would
be removed.

( Donald E. Knuth, Tracy Larrabee, and Paul M. Roberts -- Mathematical Writing )

9.3.4.6 Functions
...

 --- the optional noexcept is present if and only if the exception specification is non-throwing.

( Working Draft, Standard for Programming Language C++ N4892 )

A load succeeds if and only if the access is valid for reading 
...
loadbytes succeeds if and only if we have read permissions on the accessed memory area.
...
store preserves block validity, permissions, access validity, and bounds. Moreover, a store succeeds if and only if the corresponding access is valid for writing.

( https://compcert.org/doc/html/compcert.common.Memtype.html )

/* ** Enable ok button in a dialog box if and only if edit item
      contains text.  Edit item must have id of idEditSave */
VOID APIENTRY cDlgCheckOkEnable(
    HWND        hwnd,
    INT idEdit,
    WORD message)
{
    if (message == EN_CHANGE) {
        EnableWindow(GetDlgItem(hwnd, IDOK), (SendMessage(GetDlgItem(hwnd, idEdit), WM_GETTEXTLENGTH, 0, 0L)));
    }
}

( WinNT-related-src/leaked-src/XPSP1/shell/osshell/accesory/calendar/cdlgopen.c )

Two identifiers have the same scope if and only if their scopes terminate at the same point.

( Programming languages — C, N1570, ISO/IEC 9899:201x (AKA C11) )

NAME
 chown, fchownat — change owner and group of a file

...

Changing the group ID is permitted to a process with an effective user ID equal to the user
ID of the file, but without appropriate privileges, if and only if owner is equal to the file’s
user ID or (uid_t)−1 and group is equal either to the calling process’ effective group ID or to
one of its supplementary group IDs.

( POSIX 2017 )

Importance

This is a very important thing to use in practice, like const-correctness. It should be used as much as possible.


List of my other blog posts.