Saturday, December 12, 2020

A C# Puzzler: Records

C# version 9.0 introduces records.  Records are a computer programming concept in which a data type declaration has a number of keys which are used to define an equality operation.  Many existing languages have them (e.g. Kotlin data class, Scala case class, Java's upcoming records).  Because I stopped programming in C# before records were available, I missed using them, but now that I'm programming in Kotlin I have the pleasure of being able to use records.

Here is a little sample of some Kotlin code that exercises the record (data class) feature. It demonstrates that you can add declarations to the body without interfering with their useful semantics:

import kotlin.math.sqrt
import kotlin.collections.HashSet

public data class Cartesian(val x: Float, val y: Float) {

private var cachedR: Float = 0F
public val r: Float
get() {
var localR = cachedR;
if (localR == 0F) {
localR = sqrt(x*x + y*y)
cachedR = localR
}
return localR
}
}

fun main(args: Array<String>) {
val set = HashSet<Cartesian>()
val c1 = Cartesian(5F, 12F)
set.add(c1)
println(c1.r) // prints 13.0
println(set.contains(c1)) // prints true

val c2 = Cartesian(5F, 12F)
println(set.contains(c2)) // prints true

val c3 = c1.copy(x = 9F)
println(c3.r) // prints 15.0 }

I tried records in C# 9.0, and I was disappointed by some of the behavior.  Here is an "equivalent" fragment of C#.  Can you guess what it does?

using System;
using System.Collections.Generic;

public record Cartesian(float X, 
float Y)
{
    private 
float cachedR = 0F;
    public 
float R
    {
        get
        {
            
float r = cachedR;
            if (r == 0F)
                r = cachedR = (
float)Math.Sqrt(X * X + Y * Y);
            return r;
        }
    }
}

class Program
{
    static void Main()
    {
        var set = new HashSet<Cartesian>();
        
var c1 = new Cartesian(5, 12);
        set.Add(c1);
        Console.WriteLine(c1.R);              // 1
        
Console.WriteLine(set.Contains(c1));  // 2

        
var c2 = new Cartesian(5, 12);
        
Console.WriteLine(set.Contains(c2));  // 3

        // with expression not specified
        
var c3 = c1 with { X = 9 };           // 4
        
Console.WriteLine(c3.R);              // 5
    }
}

My hope would be that it would behave approximately the same as the Kotlin program (and the same as equivalent programs in Java or Scala).  But in C# all fields (even private ones) are considered key members of a record.  Consequently,

  1. (in the line marked "// 1") The use of the property c1.R changes the logical value of c1.
  2. Since it is not the same as the record that was added to the set, the modified record is no longer seen as a member of the set.
  3. Since the record contained in the set has been modified (records are reference types), it is no longer seen as equals to a fresh record which has not had its R property sampled.
  4. C#'s with expression produces a fresh instance with all of the fields copied, bypassing the constructor.
  5. Therefore the field cachedR is initialized to an incorrect value.

Due to these issues, programmers would be wise to use C# records in only the simplest scenarios.

Sunday, November 03, 2019

Response to letter from American Council on Science and Health.


Alex Berezow, Ph.D.
Vice President of Scientific Affairs
American Council on Science and Health
P.O. Box 1791
New York, NY  10156

Doctor Berezow-

I received with interest your letter dated June 7, 2019, on American Council on Science and Health letterhead, which began “Real scientists and trial lawyers are locked in combat. And the future of science hangs in the balance.” Much of that letter appears to repeat your article A $289M Hit Job On Science In Jackpot Verdict On Monsanto's Glyphosate.
I found your letter to contain some dubious scientific claims. Specifically, you claim that “real science proves that [cancer was caused by glyphosate is] biologically impossible.” I take several issues with this assertion. Most importantly, science does not prove anything. Proof is something to be found in the realm of mathematics, not science. Science is an inductive process by which we make hypotheses and then gather evidence to determine how likely the hypothesis is to be true or false. Scientists do not ever reach the state of having 100% proof of a hypothesis.
You also claim that there is “no credible scientific evidence [that] links glyphosate to cancer.” Perhaps you are unaware of the meta-analysis Non-Hodgkin Lymphoma and Occupational Exposure to Agricultural Pesticide Chemical Groups and Active Ingredients: A Systematic Review and Meta-Analysis published in International Journal of Environmental Research and Public Health, 2014 Apr, or the meta-analysis Exposure to glyphosate-based herbicides and risk for non-Hodgkin lymphoma: A meta-analysis and supporting evidence in Mutation Research, 2019 July-Sep. The latter is based on the most recent update of the Agricultural Health Study cohort published in 2018 and five case-control studies and found a "compelling link" between exposures to glyphosate-based herbicides and increased risk for non-Hodgkin lymphoma. Now that you are aware of them, I would ask that you tone down your rhetoric.
You also claim that “… glyphosate does not cause cancer because it doesn’t harm humans. It is an herbicide, so it is only toxic to plants. There is no known biological mechanism by which glyphosate could cause cancer, so it being a carcinogen isn’t even theoretically possible.” There is so much wrong with these assertions that it is difficult to know where to begin.
First, the opening sentence “glyphosate does not cause cancer because it doesn’t harm humans” draws a conclusion (“does not cause cancer“) based on an assertion (“doesn’t harm humans”) for which no evidence is to be found. This is the kind of statement I would expect an organization such as the Council to disavow like the junk science it seeks to fight against.
Second, the statement “It is an herbicide, so it is only toxic to plants” is also conclusory without evidence. Sure, it is sold as an herbicide. Sure, it is used as an herbicide. Sure, it is effective as an herbicide. But those facts are a non-sequitur as to whether it harms non-plants.
Finally, the claim “There is no known biological mechanism by which glyphosate could cause cancer, so it being a carcinogen isn’t even theoretically possible” appears to totally misunderstand the scientific process. Mankind has known that the sun produces light and heat for far longer than we have understood any process by which it could be “theoretically possible.” But our failure to understand how the sun produces light didn’t mean that it wasn’t obviously possible. Science infers relationships between things by observing the correlation, whether the precise mechanism of a causal relationship is known or not. Scientists form a hypothesis and then test the hypothesis by gathering data. If a causal relationship is shown to exist, the scientist might hypothesize a mechanism for the relationship. If the mechanism is shown to reliably explain the relationship, a hypothesis might graduate to the level of a theory. To suggest that glyphosate “theoretically” couldn’t be a carcinogen because we have no hypothesis for a mechanism is to turn the scientific process on its head. This hit job on science is the kind of pseudo-scientific doublespeak and emotional manipulation I would expect you to fight against.
Having said all that, I should say that the evidence for human harm I’ve seen does not rise to the level that I would support banning glyphosate. But if you’re going to resort to the ad-hominem argument that your opponent is spouting junk science to emotionally manipulate others, well then… pot, meet kettle.
Sincerely,

Neal M Gafter, Ph.D.