Как бороться с различными ошибками в статически типизированных языках (или при типизации в целом) - PullRequest
0 голосов
/ 10 марта 2020

Для контекста, мой основной язык - Python, и я только начинаю использовать аннотации. Это готовится к изучению C ++ (и потому, что, интуитивно, он чувствует себя лучше).


У меня есть что-то вроде этого:

from models import UserLocation
from typing import Optional
import cluster_module
import db
def get_user_location(user_id: int, data: list) -> Optional[UserLocation]:
    loc = UserLocation.query.filter_by(user_id=user_id).one_or_none()
    if loc:
        return loc
    try:
        clusters = cluster_module.cluster(data)
    except ValueError:
        return None # cluster throws an error if there is not enough data to cluster

    if list(clusters.keys()) == [-1]:
        return None # If there is enough data to cluster, the cluster with an index of -1 represents all data that didn't fit into a cluster. It's possible for NO data to fit into a cluster.
    loc = UserLocation(user_id=user_id, location = clusters[0].center)
    db.session.add(loc)
    db.session.commit()
    return loc

Итак, я использую typing.Optional для убедитесь, что я могу вернуть None в случае ошибки (если я правильно понимаю, эквивалент этого языка языка ввода данных c будет возвращать нулевой указатель соответствующего типа). Но как отличить guish между двумя ошибками? Например, я хотел бы вернуть -1, если недостаточно данных для кластеризации, и -2, если есть данные, но ни один из них не помещается в кластер (или что-то подобное). В Python это достаточно просто (поскольку оно не типизировано статически). Даже с mypy я могу сказать что-то вроде typing.Union[UserLocation, int].

Но как это сделать, скажем, в C ++ или Java? Может ли программист Java сделать что-то вроде установки функции, возвращающей int, и возврата идентификатора UserLocation вместо самого объекта (тогда любой код, использующий функцию get_user_location, сам выполнит поиск) ? Есть ли польза от выполнения во время выполнения или это просто реструктуризация кода, чтобы он соответствовал тому факту, что язык статически типизирован? , время компиляции и эффективность во время выполнения - но я не уверен, что делать с этой конкретной проблемой.

В двух словах: как справиться с функциями (которые возвращают небазисный тип c), указывая, что они сталкивались с различными ошибками в статически типизированных языках?

1 Ответ

2 голосов
/ 10 марта 2020

Прямой эквивалент C ++ для решения python будет std::variant<T, U>, где T - ожидаемое возвращаемое значение, а U - тип кода ошибки. Затем вы можете проверить, какой из типов содержит вариант и go оттуда. Например:

#include <cstdlib>
#include <iostream>
#include <string>
#include <variant>

using t_error_code = int;

// Might return either `std::string` OR `t_error_code`
std::variant<std::string, t_error_code> foo()
{
    // This would cause a `t_error_code` to be returned
    //return 10;

    // This causes an `std::string` to be returned
    return "Hello, World!";
}

int main()
{
    auto result = foo();

    // Similar to the Python `if isinstance(result, t_error_code)`
    if (std::holds_alternative<t_error_code>(result))
    {
        const auto error_code = std::get<t_error_code>(result);
        std::cout << "error " << error_code << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << std::get<std::string>(result) << std::endl;
}

Однако на практике это не часто встречается. Если ожидается сбой функции, то достаточно одного возвращаемого ошибочного значения, такого как итератор nullptr или end. Такие сбои ожидаются и не являются ошибками. Если сбой является неожиданным, предпочтение отдается исключениям, что также устраняет проблему, описанную здесь. Необычно ожидать и сбоя, и заботиться о деталях, почему произошел сбой.

...