Programistyczne WTF jakie Was spotkały

0

@obscurity: Ustawiłem <WarningsAsErrors>Nullable</WarningsAsErrors> oraz <TreatWarningsAsErrors>true</TreatWarningsAsErrors>:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net7.0</TargetFramework>
        <OutputType>Exe</OutputType>
        <Nullable>enable</Nullable>
        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    </PropertyGroup>
</Project>

oraz odpalilem taki kod:

using System;
using System.Text.Json;

namespace ClassLibrary1;

class Program
{
    record Value(string value);

    public static void Main()
    {
        Value value = JsonSerializer.Deserialize<Value>("{}")!;
        accept(value.value);
    }

    public static void accept(string value)
    {
        if (value == null)
        {
            Console.Write("fucked up design");
        }
        else
        {
            Console.Write("Good design");
        }
    }
}

Nie ważne czy użyję samego WarningsAsErrors, czy samego TreatWarningsAsErrors, czy obu - zawsze jest ta sama odpowiedź, czyli null wchodzi do (string value).

Comments?

1
Riddle napisał(a):
record Value(string value);

public static void Main()
{
    Value value = JsonSerializer.Deserialize<Value>("{}")!;

@Riddle: no powiedzmy. Tutaj zawiódł deserializer a Ty skłamałeś kompilator że value jest typu string a nie string?. Podobnie możesz okłamać kompilator wykrzyknikiem. Tak to niestety działa, bardziej jako pomoc w wykryciu nullów niż zapora, nadal wymaga to dużo dyscypliny żeby działało dobrze.

Powinieneś ustawić property value jako wymagany przy deserializacji:

record Value([property: JsonRequired] string value);

lub ustawić wartość początkową:

record Value(string value = "");
0
obscurity napisał(a):
Riddle napisał(a):
record Value(string value);

public static void Main()
{
    Value value = JsonSerializer.Deserialize<Value>("{}")!;

@Riddle: no powiedzmy. Tutaj zawiódł deserializer a Ty skłamałeś kompilator że value jest typu string a nie string?. Podobnie możesz okłamać kompilator wykrzyknikiem. Tak to niestety działa, bardziej jako pomoc w wykryciu nullów niż zapora, nadal wymaga to dużo dyscypliny żeby działało dobrze.

Powinieneś ustawić property value jako wymagany przy deserializacji:

record Value([property: JsonRequired] string value);

lub ustawić wartość początkową:

record Value(string value = "");

Ale widzisz że to jest obchodzenie słabego design'u typów takimi checkami? Nie po to mi statycznie typowany język, żebym musiał sam myśleć o tym gdzie dodać checki na nulla. Jakby chciał takie coś robić to bym pisał w dynamicznie typowanym języku.

Poza tym, nawet jak to dodasz, to ja ponawiam to co napisałem wcześniej:

W c#, do deklaracji (string value) nadal może wejść null.

To samo w sobie moim zdaniem jest mega słabe! Owszem, możę to obejść, ale to nie zmienia faktu że to mega słaby design.

1

@Riddle:

Offtop. Jak chcesz o tym podyskutować to pewnie już było z milion razy na forum jak ten feature wchodził.

Ten feature jest traktowany jako hint, ponieważ wszedł wiele lat później i ciężko było to zrobić inaczej aby nie zrobić rozpierdzielu w całym ekosystemie i złamać kompatybilności.

https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references

In a nullable oblivious context, all reference types were nullable. Nullable reference types refers to a group of features enabled in a nullable aware context that minimize the likelihood that your code causes the runtime to throw System.NullReferenceException. Nullable reference types includes three features that help you avoid these exceptions, including the ability to explicitly mark a reference type as nullable:

that minimize the likelihood that your code causes the runtime to throw

minimize the likelihood

The null-state analysis provides robust analysis for most variables. The compiler needs more information from you for member variables. The compiler can't make assumptions about the order in which public members are accessed. Any public member could be accessed in any order. Any of the accessible constructors could be used to initialize the object. If a member field might ever be set to null, the compiler must assume its null-state is maybe-null at the start of each method.

You use annotations that can declare whether a variable is a nullable reference type or a non-nullable reference type. These annotations make important statements about the null-state for variables:

A nullable reference type is noted using the same syntax as nullable value types: a ? is appended to the type of the variable. For example, the following variable declaration represents a nullable string variable, name:

string? name;

0
WeiXiao napisał(a):

@Riddle:

Offtop. Jak chcesz o tym podyskutować to pewnie już było z milion razy na forum jak ten feature wchodził.

Ten feature jest traktowany jako hint, ponieważ wszedł wiele lat później i ciężko było to zrobić inaczej aby nie zrobić rozpierdzielu w całym ekosystemie i złamać kompatybilności.

https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references

In a nullable oblivious context, all reference types were nullable. Nullable reference types refers to a group of features enabled in a nullable aware context that minimize the likelihood that your code causes the runtime to throw System.NullReferenceException. Nullable reference types includes three features that help you avoid these exceptions, including the ability to explicitly mark a reference type as nullable:

that minimize the likelihood that your code causes the runtime to throw

minimize the likelihood

Zgadzam się.

Ale w żaden sposób to nie zmienia tego że to jest mega słabe rozwiązanie.

0

Z ciekawości, czy obecnie w Javie jest null safety?

2
Riddle napisał(a):

Nie po to mi statycznie typowany język, żebym musiał sam myśleć o tym gdzie dodać checki na nulla. Jakby chciał takie coś robić to bym pisał w dynamicznie typowanym języku.

Bardzo wiele statycznie typowanych języków ma wsparcie dla null.
Zapewne też istnieją dynamiczne języki, które tego nie wspierają.

to nie zmienia faktu że to mega słaby design.

Jedyny możliwy w tej sytuacji.

0

Mnie to zawsze intrygowało, @somekind na pewno wie czemu tak jest:

  • dlaczego akurat tylko string jest tu jakimś szczególnym przypadkiem
  • dlaczego warningi zamiast błędów kompilacji i jaki problem, żeby stare biblioteki były bez null safety, a twój kod miał to włączone? Chyba że wszytkie zależności muszą używać tej samej wersji języka. Warningi zamiast błędów to zły design. Traktowanie wszytkich (bez wyjątku) warningów jako błędów to niekoniecznie coś, czego zawsze chcesz

Dobry design to wszytko domyślnie nie nullable, a dopiero jak chcesz żeby było nullable to tak to definiujesz. I błędy kompilacji, bo przypisanie np nulla do zmiennej która nie jest nullable nie ma prawa się skompilować.
No ale z tego co tu czytam, to można tak ustawić, oprócz stringa bo ze stringami jest jakiś szczególny problem.

2
gajusz800 napisał(a):

Mnie to zawsze intrygowało, @somekind na pewno wie czemu tak jest:

  • dlaczego akurat tylko string jest tu jakimś szczególnym przypadkiem

Nie tylko string, każda inna klasa też.
I to nie jest nic niesamowitego, że typy referencyjne mogą przechowywać null. To nie jedyny język, w którym tak to działa.

  • dlaczego warningi zamiast błędów kompilacji

Bo to po pierwsze łamie kompatybilność wsteczną, a po drugie niczego nie gwarantuje, jedynie podpowiada potencjalne pomyłki w Twoim kodzie.

  • i jaki problem, żeby stare biblioteki były bez null safety, a twój kod miał to włączone?

To nie jest problem, tak się właśnie z tym pracuje.

Dobry design to wszytko domyślnie nie nullable, a dopiero jak chcesz żeby było nullable to tak to definiujesz. I błędy kompilacji, bo przypisanie np nulla do zmiennej która nie jest nullable nie ma prawa się skompilować.

Tak, tylko do tego trzeba mieć nowy język, a nie istniejący, który nulle ma od początku.

2
Riddle napisał(a):

Zgadzam się.

Ale w żaden sposób to nie zmienia tego że to jest mega słabe rozwiązanie.

Włączenie nullable dodaje statyczną analizę na etapie kompilacji, a nie na runtime. Oznacza to, że kompilator nie jest w stanie wykryć jeżeli ustawisz coś przez refleksję. A to właśnie JsonSerializer robi. Dla mnie to jest twoje niezrozumienie mechaniki, bo nie oznaczyłeś tej właściwości jako nullable, a że obiekt jest deserializowany, to jak najbardziej null się może pojawić.

4

Kiedy na stare lata czlowiek odkrywa, ze nie rozroznia zielonego koloru (Kraków): IMG_20230817_132113836.jpg

2

Może nie typowo programistyczne, ale pokrewne. Dałem ziomkowi zadanie: porównaj throughput naszej aplikacji na różnych implementacjach JVM w zależności od algorytmu GC i systemowego allokatora pamięci (malloc vs jemalloc). Poszedłem na urlop, wracam, a tam mail 'Sukces testów!'... zaś w załączniku klika screenshotów jak załadował randomowego loga GC do narzędzia wizualizującego logi GC. Teraz +1exp i wiem, że takich zadań nie można dawać.

0

https://jajestemzagrozeniem.pl/#generator jest sobie stronka polityczna, ale fajne rzeczy ukrywa :D

screenshot-20230906214544.png
screenshot-20230906215114.png

1

Wpisuje w konsolę

sbt new UdashFramework/udash.g8

rozpoczyna się świąganie szablonowego projektu z gita, dużo sukcesów i nagle:

org.eclipse.jgit.api.errors.TransportException: [email protected]:UdashFramework/udash.g8.git: Algorithm negotiation fail

Jaki mozna mieć Algorithm negotiation fail podczas ściągania publicznego szablonu projektu z githuba to ja nie wiem :D

2

Ten kod powinni na studiach pokazywać studentom informatyki, jako przykład jak nie należy pisać. A na anty-przykładach można się dużo nauczyć.

  1. skróty są przydatne, ale jak robisz zmienne w stylu PKP stprzN czy odjprz albo wyrzgody to już coś jest nie tak
  2. pracując w zespole (a nawet w pojedynkę) warto się trzymać standardów, a nie że ktoś będzie pisał camelCase, a ktoś inny w underscore_case
  3. warto trzymać się idiomów danego języka i jeśli w jakimś języku jest true/false to tego używać, a nie wymyślać sobie nowy typ boolean bez potrzeby:
var OK = 1;
var NO = 0;
  1. formatowanie i styl też warto dopasować do języka, a nie robienie zagnieżdżania ifów jak w jakimś Pascalu
  2. warto wydzielać funkcjonalności do jednego miejsca i zadbać o czytelność rozwiązania (np. regexp do walidowania emaila jest w każdym miejscu inny. A najdłuższa jego wersja jest praktycznie nie do odczytu)
  3. język polski się nie nadaje do pisania kodu. Lepiej pisać wszystko po angielsku.

To jest tak piękny w swoim zepsuciu kod, że nawet osoby początkujące w programowaniu nie są w stanie wymyślić tylko różnych złych praktyk naraz. Obstawiam, że był on zrobiony przez kilka osób (o czym sądzi niespójność i nagromadzenie różnych podejść i preferencji) i osoby te były jakimiś kiepskimi programistami, ale myślę, że nie byli to całkiem nowicjusze (już to wymyślenie swojego booleana sugeruje, że ktoś pisał wcześniej w czymś innym np. w C i chciał odtworzyć to podejście).

4

@LukeJL:

język polski się nie nadaje do pisania kodu. Lepiej pisać wszystko po angielsku.

zagram adwokata diabła - jeżeli masz domenę bardzo mocno powiązaną z polską i polską nomenklaturą (prawo, kadry, whatever)

to czy w takiej sytuacji nie utrudniasz sobie pisząc kod po angielsku?

No bo co do zasady argument za pisaniem kodu po angielsku nie jest techniczny, a jedynie związany z zatrudnianiem nowych ludzi do zespołu.

0

@WeiXiao: miałem dokładnie ten przypadek. W takiej sytuacji część kolumn w bazie i przez to zmiennych miała "polskie" nazwy, ale to tyle, nie szedłem w żadne ekstrema, żeby pisać lacznieSprawOC = ... i ogólnie pół kodu po polsku

0
WeiXiao napisał(a):

@LukeJL:

język polski się nie nadaje do pisania kodu. Lepiej pisać wszystko po angielsku.

zagram adwokata diabła - jeżeli masz domenę bardzo mocno powiązaną z polską i polską nomenklaturą (prawo, kadry, whatever)

to czy w takiej sytuacji nie utrudniasz sobie pisząc kod po angielsku?

200% tak
I znakomicie zwiększając ryzyko błędnej translacji - tj międzyludzkiej.

Ojciowskie / tacierzyński (dokładnie w tej odmianie)

3
WeiXiao napisał(a):

to czy w takiej sytuacji nie utrudniasz sobie pisząc kod po angielsku?

A czy ułatwieniem jest pisanie tego typu zmiennych?
stprzN czy odjprz albo wyrzgody
Już po chińsku byłoby bardziej zrozumiałe, bo wtedy można byłoby by sprawdzić w słowniku przynajmniej. Co to są wyrzgody? Pewnie z kontekstu można wyłapać, ale to utrudnianie sobie życia właśnie. Skróty są spoko, jeśli są powszechnie zrozumiałe (np. environment -> env), są elementem konwencji (np. matematycznej) albo jeśli nie wychodzą poza kilka linijek lokalnego kodu. Ale walić randomowe skróty, bo ktoś miał natchnienie, to raczej nie bardzo.

zagram adwokata diabła - jeżeli masz domenę bardzo mocno powiązaną z polską i polską nomenklaturą (prawo, kadry, whatever)

Nie wiem, pewnie zależy co. Co innego jak coś jest typowo polskie jak pesel czy nip, a co innego jest podróżny czy pies. Przecież na całym świecie ludzie podróżują i są psy.

A raczej wolałbym taki kod:

if (shouldApplyPolskiLad) {
    addPierogi();
}

(czyli kod w 100% po angielsku za wyjątkiem słownictwa domenowego)
niż taki

if (powinienZastosowacPolskiLad) {
    dodajPierogi();
}

(100% po polsku)

a już na pewno nie taki:

if (powzastPolLad) {
    dodPier();
}

(100% po polsku + skróty)

czy taki:

if (shouldStosowanie_PolskiLad) {
  dodaj_dumplings();    
}

(pomieszanie angielskiego z polskim).

2 ostatnie propozycje to tragedia, a rzeczy w podobnym stylu są na stronie PKP.

7

@LukeJL:

A czy ułatwieniem jest pisanie tego typu zmiennych?
stprzN czy odjprz albo wyrzgody

Gówniane skróty są słabe niezaleznie od jezyka.

2

Kod przed:

/**
* This class Generates prime numbers up to a user specified
* maximum. The algorithm used is the Sieve of Eratosthenes.
* <p>
* Eratosthenes of Cyrene, b. c. 276 BC, Cyrene, Libya --
* d. c. 194, Alexandria. The first man to calculate the
* circumference of the Earth. Also known for working on
* calendars with leap years and ran the library at Alexandria.
* <p>
* The algorithm is quite simple. Given an array of integers
* starting at 2. Cross out all multiples of 2. Find the next
* uncrossed integer, and cross out all of its multiples.
* Repeat untilyou have passed the square root of the maximum
* value.
*
* @author Alphonse
* @version 13 Feb 2002 atp
*/

public class GeneratePrimes {
  public static int[] generatePrimes(int maxValue) {
    if (maxValue >= 2) // the only valid case
    { 
	  // declarations
      int s = maxValue + 1; // size of array
      boolean[] f = new boolean[s];
      int i;
	  
      // initialize array to true.
      for (i = 0; i < s; i++)
        f[i] = true;
		
      // get rid of known non-primes
      f[0] = f[1] = false;
	  
      // sieve
      int j;
      for (i = 2; i < Math.sqrt(s) + 1; i++) {
        if (f[i]) // if i is uncrossed, cross its multiples.
        {
          for (j = 2 * i; j < s; j += i)
            f[j] = false; // multiple is not prime
        }
      }
	  
      // how many primes are there?
      int count = 0;
      for (i = 0; i < s; i++) {
        if (f[i])
          count++; // bump count.
      }
	  
      int[] primes = new int[count];
	  
      // move the primes into the result
      for (i = 0, j = 0; i < s; i++) {
        if (f[i]) // if prime
          primes[j++] = i;
      }
	  
      return primes; // return the primes
    } else // maxValue < 2
      return new int[0]; // return null array if bad input.
  }
}

Kod po ""refaktorze""

/**
* This class Generates prime numbers up to a user specified
* maximum. The algorithm used is the Sieve of Eratosthenes.
* Given an array of integers starting at 2:
* Find the first uncrossed integer, and cross out all its
* multiples. Repeat until there are no more multiples
* in the array.
*/

public class PrimeGenerator {
  private static boolean[] crossedOut;
  private static int[] result;
  
  public static int[] generatePrimes(int maxValue) {
    if (maxValue < 2)
      return new int[0];
    else {
      uncrossIntegersUpTo(maxValue);
      crossOutMultiples();
      putUncrossedIntegersIntoResult();
      return result;
    }
  }
  
  private static void uncrossIntegersUpTo(int maxValue) {
    crossedOut = new boolean[maxValue + 1];
    for (int i = 2; i < crossedOut.length; i++)
      crossedOut[i] = false;
  }
  
  private static void crossOutMultiples() {
    int limit = determineIterationLimit();
    for (int i = 2; i <= limit; i++)
      if (notCrossed(i))
        crossOutMultiplesOf(i);
  }
  
  private static int determineIterationLimit() { 
    // Every multiple in the array has a prime factor that
    // is less than or equal to the root of the array size,
    // so we don't have to cross out multiples of numbers
    // larger than that root.
    double iterationLimit = Math.sqrt(crossedOut.length);
    return (int) iterationLimit;
  }
  
  private static void crossOutMultiplesOf(int i) {
    for (int multiple = 2 * i; multiple < crossedOut.length; multiple += i)
      crossedOut[multiple] = true;
  }
  
  private static boolean notCrossed(int i) {
    return crossedOut[i] == false;
  }
  
  private static void putUncrossedIntegersIntoResult() {
    result = new int[numberOfUncrossedIntegers()];
    for (int j = 0, i = 2; i < crossedOut.length; i++)
      if (notCrossed(i))
        result[j++] = i;
  }
  
  private static int numberOfUncrossedIntegers() {
    int count = 0;
    for (int i = 2; i < crossedOut.length; i++)
      if (notCrossed(i))
        count++;
    return count;
  }

ten refaktor pochodzi z "czystego kodu"

4

Czemu do luja w PHP argumenty w explode() idą (needle, string) a w strPos() idą (string, needle) :|

Najgorzej zdesignowany język na świecie.

0

Miałem dzisiaj lekkie wtf na rozmowie rekrutacyjnej, gdy rekruter zadał mi pytanie: "jak zoobrazujesz relacje OneToMany z poziomu kodu w Javie?", Odpowiedziałem, że wstawię nowe pole do encji typu Set z odpowiednią encja w typie genetycznym i dodam do tego adnotacje @OneToMany itd. (Myślę, że w miare standardowe rozwiązanie), na co on się nie zgodził i uznał, że powinno to być zrobione w pośredniej tabeli gdzie trzymamy klucze obce z obu tabel (czyt. User -> Produkty [] jest ble, lepiej zrobić, ProduktyUsera z id usera i produktu), i teraz mam pytanie o zasadność jego podejścia do szanowanych użytkowników i kiedy jest to lepsze podejście a kiedy nie jest

0
too many elements for tuple: 28, allowed: 22
    override def * : ProvenShape[MY_ENTITY] = (

moja encja ma więcej niż 22 elementy czyli niż implementacja tupli w Scali więc standardowa konwersja w Slicku (MY_ENTITY.tupled, MY_ENTITY.unapply) przestaje działać :(

4

Kolega devops stal sie programista na polecenie klienta. W niedziele siadam do zaleglego tematu bo mnie oswiecilo. Zacommitowalem zmiany. Domergowalem developa. Zapuscilem testy i zonk bo kilka failuje. Pozno bylo wiec odlozylem temat do rana. Wstalem, zaglebilem sie w kod, asercje tak popisane ze w tygodniu dzialaja, a w weekendy failuja.

6
<div class="col-12">
  <div class="box">
    <h2 class="h4"><i class="fas fa-star fa-fw"></i></h2>
  </div>
</div>

Nie ma to jak <h2> ale z klasą "h4".

Zmiana dodana w commicie "Improved page headers".

0

PKP. Nie mogę kupić biletu na takie połączenie:
screenshot-20231002214823.png
bo przejazd odbywa się dwa razy na tym samym odcinku.
screenshot-20231002214852.png
Ograniczenie biznesowe?! Technologiczne?

0

Zainstalowałem sobie Ubuntu na drugim kompie, podłączam monitory i widzę
20231007_115037.jpg

Co do to ma być? To ma być najlepsza dystrybucja linuxa? Nie widziałem wcześniej OS który by odwalał takie coś.

1

Cały ten filmik: www.youtube.com/watch?v=oteQXOBHflU.

Nie zgadniecie jaki ma tytuł.

1 użytkowników online, w tym zalogowanych: 0, gości: 1