So profitieren Sie von statischer Typisierung

Typbegrenzte Live-Daten fließen von Bundesstaat zu Bundesstaat
Typbegrenzte Live-Daten fließen von Bundesstaat zu Bundesstaat

In diesem Artikel erfahren Sie, wie Sie das statische Typsystem beim Entwerfen Ihres Codes optimal nutzen können. Der Artikel versucht sprachunabhängig zu sein (es funktioniert nicht immer), Beispiele sind in Java und stammen aus dem Leben. Obwohl akademische Sprachen wie Idris es uns ermöglichen, nützlichere Tricks mit statischer Typisierung zu machen , und die vollständige Typinferenz die Größe der Zeremonie erheblich reduziert , schreiben wir bei der Arbeit in anderen Arten von Sprachen und möchten in der Lage sein, gute Kenntnisse anzuwenden in der Praxis, weil es unser Leben heute verbessern wird. ...





Kurze Nacherzählung der Handlung des Artikels

, , , , , .





, - ( , ). , , .





, .. , . .





, . , .





, : , ( , , , Java) .





, , , .





:





  1. : , .





  2. , , , .





  3. . — , . — .





  4. , .





  5. , .





  6. : DSL, .





  7. .





, .





, , , . Rust ( non lexical lifetimes: , , , ), . ( ": "). , , , , , , .





, , , .. .





, : , , , . :





, , : , Rust , , .





, , , . . , . , , .





Java:





Optional<? extends CharSequence> x = getContent();
/*
   : 
incompatible types: java.lang.String cannot be converted to
capture#1 of ? extends java.lang.CharSequenc
*/
CharSequence y = x.orElse("");
//       :
// CharSequence y = ( (Optional<CharSequence>) x).orElse("");
      
      



, . , , .





, , .





x



Optional



maybe Java, Rust Scala Option



. C# , , nullable , Optional



. Optional.orElse



, null



, .





? extends CharSequence



, , CharSequence



. Java ""



String



, CharSequence



.





, CharSequence



x



y



, ""



. . Java .





, .. CharSequence



, CharSequence



. Optional



. , .





. , , . C, , , , , .





, C++ Java : , , . , , , .





.





Typischer logischer Fehler

, . , , . , , .





, , , . , , , , — .





Ich will alles auf einmal

, : " "? — , , .





: , , . , , : -, , -, , -, , - . , , , .





, , , — , , , .





Wir werden uns hauptsächlich für universellen Polymorphismus interessieren

C Java? , C , ? . C , , . , , . , , , - :





void qsort (
    void* base, 
    size_t num, 
    size_t size, 
    int (*comparator)(const void*, const void*)
);
      
      



. void*



.





, , . , ad-hoc , , C ( , ). - .





Java 3 . : ( ) ( ), ad-hoc: .





, .





— . , . , , : . , Rust , .





, , , .





Rust , : .. ( ) .





Java , , , :





class Builder {
    void addNames(String... names) {addNames(List.of(names))}
    void addNames(Iterable<String> names) {/*...*/}
}
      
      



, , . : , , , .





, - . , -, .





: , , , .





, :





//  run    String  T   T   .
<T> T run(Function<String, T> x) {
    return x.apply("");
}

//  run    String  ,
//          .
void run(Consumer<String> x) {
    run(y-> {
        x.accept(y);
        return null;
        });
}
    
void doWork() {
    run(x-> System.out.println(x));             //  .
    run((String x)-> System.out.println(x));    //    .
}
      
      



— : . Java , run(Function)



run(Consumer)



, , : run(Consumer)



, , .. , , run(Function)



. , , , -, , .





, , .





, - , . , — , — . , , , .





.





, , , . . - . , .





, ClassA



, ClassB



, ClassC



. foo



, bar



, baz



. foo



bar



, baz



. ClassB



foo



baz



, ClassC



baz



, , ClassC.foo()



. : ClassC.foo()



ClassB.foo()



ClassA.bar



ClassA.baz



, ClassC.baz



. , , , .





Selbst mit einem Bild ist es nicht sofort klar, oder?
, ?

, , , . , .





— , .





, . : , , , API.





List.of



— Java, List



. , . List12



, 2 , , , . , .





— , , , ++ . , . , . , , , , .





, , language agnostic , java- , . , , .









, List<T>



, : X



Y



. , List<X>



, List<Y>



? , , — . , X



Z



, , List<Y>



, List<X>



: Z



, List<Y>



. , java heap pollution. ( , )





, , .





, .





:





  1. — : , . Java .





  2. — , List<Y>



    . . Java List<? extends X>



    .





  3. — , List<Y>



    List<X>



    . . Java List<? super Y>



    .





Rust, , . Java C# . .





, , , Java . , Kotlin . , ( ) Java .





Java. List<? extends X>



- , heap pollution. Java : , , null



. : , null



, , (.. List<? extends X>



X



).





orElse(T default)



: T



? extends CharSequence



null



, T get()



CharSequence



. Java — , , . null



heap pollution.





: List<? super Y>



add(T)



Y



, T get(int)



Object



. , Y



List<Y>



, List<X>



List<Object>



, , get



.





, , . , , .. heap pollution .





, — , .









. , List<Y>



List<? extends X>



, . , Map<K, List<X>>



, Map<K, List<Y>>



, : Map<K, ? extends List<? extends X>>



. , . Map<K, List<? extends X>>



, Map<K, List<Y>>



, Map<K, List<X>>



, .. List<? extends X>



, , .









, . , , var



( ). , .





.









Rust C++ / , . .





Java . , , , , .





C

, , .





, , T



source



, blacklist



. :





<T> int filterCount(Collection<T> source, Set<T> blacklist) {
    if (blacklist.isEmpty()) {
        return source.size();
    }
   return (int) source.stream().filter(x->!blacklist.contains(x)).count();
}
      
      



, blacklist



Set



.





Java, , : Collection



, Set



, List



. Collection



contains



, Set



.





, contains



Set



: O(1) HashSet



O(log n) TreeSet



. - Set



-, , Set



. .





, : . , , Java , .





,

, : - - , . - , .





, : . String->String



, , - : .





: SchemaDiff



String name



Nullable



.





final class SchemaDiff {
    final String name;
    final @Nullable String oldType;
    final @Nullable String newType;

    SchemaDiff(
        String name, 
        @Nullable String oldType, 
        @Nullable String newType
    ) {
        this.name = name;
        this.oldType = oldType;
        this.newType = newType;
    }

    @Override
    public String toString() {
        if (oldType != null && newType != null) {
            return String.format(
                "Column %s changed the type: %s->%s",
                name,
                oldType, 
                newType
            );
        }
        if (oldType == null) {
            return String.format(
                "Column %s with type %s has been added", 
                name, 
                newType
            );
        }
        return String.format(
            "Column %s with type %s has been removed", 
            name, 
            oldType
        );
    }
}
      
      



null



. NPE: Optional



, .. : null



, , , , null



, .





toString



. , , oldType



null



.





, , : RemovedColumn



, AddedColumn



TypeChanged



. SchemaDiff



, .





abstract class SchemaDiff {
    final String name;

    protected SchemaDiff(String name) {
        this.name = name;
    }
}

final class RemovedColumn extends SchemaDiff {
    final String type;

    RemovedColumn(String name, String type) {
        super(name);
        this.type = type;
    }

    @Override
    public String toString() {
        return String.format(
            "Column %s with type %s has been removed", 
            name, 
            type
        );
    }
}

final class AddedColumn extends SchemaDiff {
    final String type;

    AddedColumn(String name, String type) {
        super(name);
        this.type = type;
    }

    @Override
    public String toString() {
        return String.format(
            "Column %s with type %s has been added", 
            name, 
            type
        );
    }
}

final class TypeChanged extends SchemaDiff {
    final String oldType;
    final String newType;

    TypeChanged(String name, String oldType, String newType) {
        super(name);
        this.oldType = oldType;
        this.newType = newType;
    }

    @Override
    public String toString() {
        return String.format(
            "Column's %s type has been changed: %s->%s", 
            name, 
            oldType, 
            newType
        );
    }
}
      
      



, , . toString



.





, , , . . , , — .





, .





Jeder Polymorphismus ermöglicht es Ihnen, dasselbe bis zu Arten von Berechnungsdiagrammen in einem Diagramm zusammenzufassen

- , :





void process(List<Item> items) {
    if (isLegacy) {
        List<Legacy> docs = items.stream()
            .map(x -> toLegacy(x))
            .collect(toList);
        legacyTable.store(docs);
        logEvent(docs.stream().map(x->x.getId()).collect(toList()));
    } else {
        List<Modern> docs = items.stream()
            .map(x->toModern(x, context))
            .collect(toList);
        modernTable.store(docs);
        logEvent(docs.stream().map(x->x.getId()).collect(toList()));
    }
}
      
      



, Legacy



Modern



. toLegacy



toModern



, . legacyTable



modernTable



, .





- . : , - — .





— — .





, :





<T extends WithId> List<T> store(
    List<Item> items,
    Function<Item, T> mapper,
    Table<T> table
) {
    result = items.map(mapper).collect(toList());
    table.store(result);
    return result;
}
      
      



:





void process(List<Item> items) {
    List<? extends WithId> docs = isLegacy ?
        store(items, x -> toLegacy(x), legacyTable) : 
        store(items, x -> toModern(x, context), modernTable);
    logEvent(docs);
}
      
      



logEvent



, , id



.





, - , .. , .





, , var



Kotlin, C# Java, , .. "" : .





Java:





var list = new ArrayList<>(); //   list    ArrayList<Object>.
list.add(1);
      
      



Rust:





let mut vec = Vec::new();   // vec    Vec<i32>
vec.push(1);
      
      



, , . .





. , , :





HashMap<String, String> map = new HashMap<>();
      
      



:





Map<String, String> map = new HashMap<>();
      
      



: HashMap



TreeMap



- Map



, . , , .





Java 11 , , var



, .





, - :





Long2LongOpenHashMap createMap(long[] keys, long[] values);
      
      



- long->long



- -. , .. , . , .





, , , .





Long2LongMap createMap(long[] keys, long[] values);
      
      



- :





var map = createMap(keys, values);
for(long x: xs) {
    f(map.get(x));
}
      
      



! , , .. API . , — - ( ).





, . , ML- , API . , . — . , — , . -.





, , enum-:





enum FeatureType {
    ELMO,
    SLANG,
    LIFETIME_7D,
}
      
      



. , ELMO



EmbeddingEntry



— float, LIFETIME_7D



FloatEntry



, float



— , 7 , SLANG



BlacklistEntry



— . FeatureEntry



, id



, .





, , API:





<TEntry extends FeatureEntry> Collection<TEntry> find(Collection<Id> ids, FeatureType type);
      
      



id



. .





: TEntry



FeatureType



? , :





enum FeatureType() {
    ELMO(EmbeddingEntry.class),
    SLANG(BlacklistEntry.class),
    LIFETIME_7D(FloatEntry.class),
    ;

    private final Class<? extends FeatureEntry> entryClass;

    public FeatureType(Class<? extends FeatureEntry> entryClass) {
        this.entryClass = entryClass;
    }

    public Class<? extends FeatureEntry> getEntryClass() {
        return entryClass;
    }
}
      
      



, , enum-. , .





, . find



TEntry



, . 3, 56, , .





:





final class FeatureType<TEntry extends FeatureEntry> {
    public static final FeatureType<EmbeddingEntry> ELMO = 
        new FeatureType("elmo", EmbeddingEntry.class);
    public static final FeatureType<BlacklistEntry> SLANG = 
        new FeatureType("slang", BlacklistEntry.class);
    public static final FeatureType<FloatEntry> LIFETIME_7D = 
        new FeatureType("lifetime_7d", FloatEntry.class);

    private final Class<TEntry> entryClass;
    private final String name;
    private FeatureType(String name, Class<TEntry> entryClass) {
        this.name = name;
        this.entryClass = entryClass;
    }

    public String getName() {
        return name;
    }

    public Class<TEntry> getEntryClass() {
        return entryClass;
    }
}
      
      



: , enum. — — API :





<TEntry extends FeatureEntry> Collection<TEntry> find(
   Collection<Id> ids, 
   FeatureType<TEntry> type
);
      
      



API, , - . , , API.





, , - - , , ( Java). .





, " ", , , .





. :





static <TLeft, TRight, TResult> 
BiFunction<Optional<TLeft>, Optional<TRight>, Optional<TResult>> 
lift(BiFunction<TLeft, TRight, TResult> function) {
    return (left, right) -> left.flatMap(
        leftVal -> right.map(rightVal -> function.apply(leftVal, rightVal))
    );
}
      
      



, Optional



.





, FeatureType



, "" FeatureType



FeatureEntry



. , FeatureType



, "" FeatureEntry



.





, , . , , , . , , . , - , . ML .





:





<TEntry extends FeatureEntry> Collection<TEntry> find(
    Collection<Id> ids, 
    FeatureType<TEntry> type, 
    Language language
);

<TEntry extends FeatureEntry> Collection<TEntry> find(
    Collection<Id> ids, 
    FeatureType<TEntry> type, 
    Country country
);
      
      



: , runtime , .





:





class FeatureType<TEntry extends FeatureEntry> {
    public static final ByLanguage<EmbeddingEntry> ELMO =
        new ByLanguage<>("elmo", EmbeddingEntry.class);
    public static final ByCountry<BlacklistEntry> SLANG = 
        new ByCountry<>("slang", BlacklistEntry.class);
    public static final ByCountry<FloatEntry> LIFETIME_7D = 
        new ByCountry<>("lifetime_7d", FloatEntry.class);

    private final Class<TEntry> entryClass;
    private final String name;
    private FeatureType(String name, Class<TEntry> entryClass) {
        this.name = name;
        this.entryClass = entryClass;
    }

    public String getName() {
        return name;
    }

    static final class ByLanguage<TEntry extends FeatureEntry>
        extends FeatureType<TEntry> {...}
    static final class ByCountry<TEntry extends FeatureEntry> 
        extends FeatureType<TEntry> {...}
}
      
      



API :





<TEntry extends FeatureEntry> Collection<TEntry> find(
    Collection<Id> ids, 
    FeatureType.ByLanguage<TEntry> type, 
    Language language
);

<TEntry extends FeatureEntry> Collection<TEntry> find(
    Collection<Id> ids, 
    FeatureType.ByCountry<TEntry> type, 
    Country country
);
      
      



.





. , , , , , , .





, . , enum . , - , . , , . . , , .





-, , . , Java generic enum- , — , . , .





— . . , , , -, .





— , - — . , ? ? ? , , ? .





, -, , .





. , heap dump-, . heap dump- - : , . , heap dump- , , LevelDB, .





, , , . , , , Inspection



, , API Inspection



, : , UI.





— , — . , , .





, : - . , , -.





Unten rechts nicht der Manager, sondern Shoggot
,

DSL vs composability

, - . , , , Java . , - DSL composability ( ).





DSL : , , API, - DSL. , , - , - DSL. , .. , DSL , .





- , , — . , composability.





, , : CompletableFuture<Optional<T>>



. Java :





  1. OptionalFuture



    .





  2. - FutureUtils



    .





-. composable. , OptionalFuture



CompletableFuture



, Optional



CompletableFuture



, . , - CompletableFuture



, , thenCompose



( ), , .





Java, composable : , . , , . -, vs . , , .





, , , composability , . , Apache Lucene.





Apache Lucene — : Twitter, Elasticsearch. , : , — . — API.





, , , , - - : ( Java), ( , , T[]



int[]



) , ( ).





, , , . , ? , Java " T, T, ", .





Apache Lucene InPlaceMergeSorter, , :





//   :
private BlendedTermQuery(Term[] terms, float[] boosts, TermStates[] contexts) {
    assert terms.length == boosts.length;
    assert terms.length == contexts.length;
    this.terms = terms;
    this.boosts = boosts;
    this.contexts = contexts;
    //  terms, boosts  contexts    

    
    //     :      .
    new InPlaceMergeSorter() {
      //     terms,     .
      @Override
      protected int compare(int i, int j) {
        return terms[i].compareTo(terms[j]);
      }

     //         ,      terms
     @Override
      protected void swap(int i, int j) {
        Term tmpTerm = terms[i];
        terms[i] = terms[j];
        terms[j] = tmpTerm;

        TermStates tmpContext = contexts[i];
        contexts[i] = contexts[j];
        contexts[j] = tmpContext;

        float tmpBoost = boosts[i];
        boosts[i] = boosts[j];
        boosts[j] = tmpBoost;
      }
    //   , ..  : -.
    }.sort(0, terms.length);
  }
      
      



, , , . , .





API , , , - - , . API: , , — .





API , :





Foo(float[] boosts) {
    this.boosts = boosts.clone();

    new InPlaceMergeSorter() {
      @Override
      protected int compare(int i, int j) {
        return Float.compare(boosts[i], boosts[j]);
      }

      @Override
      protected void swap(int i, int j) {
        float tmpBoost = this.boosts[i];
        this.boosts[i] = this.boosts[j];
        this.boosts[j] = tmpBoost;
      }
    }.sort(0, terms.length);
  }
      
      



, , .. boosts



this.boosts



, .





. , , , , .





- , , . , - composability, composability, .





API . .





, , , . , , , . , . : , . , , , .





, , , , . , null



null



. . , , , . , , ? , . : UB , null, , , .





, , . , , 1 , . , -, , , .. , . Java.





P.S.

C. .





Vielen Dank an diese Personen für die Überprüfung des Artikels vor der Veröffentlichung:





  1. Dmitry Yudakov





  2. Dmitry Petrov





  3. Nikolay Mishuk





  4. Anastasia Pavlovskaya





  5. Polina Romanchenko





  6. Svetlana Yesenkova





  7. Yan Kornev








All Articles