LINUX.ORG.RU
ФорумTalks

ООП. Иерархия геометрических фигур.

 ,


0

0

Итт мастера правильной™ ооп архитектуры рассказывают неучам-птушникам, как правильно сделать иерархию фигур Евклидовой геометрии. Для начала рассмотрим следующие фигуры: квадрат, прямоугольник, ромб, трапеция. Каждому нужно сделать класс, который будет, как минимум, будет иметь методы расчёта площади и пересечения с другой фигурой. Естественно, начальные требования могут и будут расширяться.

Ожидается, что адепты ооп продемонстрируют всякие ништяки типа реюзабельности кода и возможности простого расширения без переписывания всего проекта.

Положение хера на основные принципы ООП (инкапсуляция, полиморфизм, наследование), естественно, является признанием несостоятельности этого самого ООП, как целостной концепции.

Да начнётся срач! /дныньк/

★★★★★

Последнее исправление: alpha (всего исправлений: 1)
Ответ на: комментарий от ya-betmen

Ну в книжках по программированию, особенно если они называются «основы ООП» такого всё-таки не должно быть. Можно подобрать более удачные примеры.

no-such-file ★★★★★
()
Ответ на: комментарий от crutch_master

Вычисление площади треугольника и ромба.

В гугле мне выкинуло 7 формул для расчета ромба, некоторые из них эффективнее расчета через площадь треугольника. Но допустим даже вот это:

Площадь квадрата - частный случай площади прямоугольника.

Создаёшь абстрактный класс Rectangable и защищённый метод square(a, b) { return a * b; }

Наследуешь его квадратом и прямоугольником.

С треугольником и ромбом также square(b, h, boolean pair).

То, что в джаве нельзя наследовать несколько абстрактных классов - отдельный разговор. Можно выкрутиться через дефолтные методы в интерфейсе, но тоже не вариант светить защищёнными методами.

С другой стороны можно сделать так:

interface Triangable
int b()
int h()
boolean pair()

default int square() {...}
foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 2)
Ответ на: комментарий от foror

также square(b, h, boolean pair)

Так это не также, интерфейс другой, Лисков посылает тебе лучи поноса. Правильнее всё-таки сделать классы калькуляторов площади с интерфейсом вроде

square.param(1, a).param(2, b).calc()
no-such-file ★★★★★
()
Ответ на: комментарий от Nervous

Оно не для этого. Оно для реализации механизмов композиции. Я подробнее потом напишу. Это не совсем то, что может сразу в голову прийти.

aist1 ★★★
()
Ответ на: комментарий от foror

В гугле мне выкинуло 7 формул для расчета ромба, некоторые из них эффективнее расчета через площадь треугольника

У ромба равные стороны, ему соответствует равнобедренный треугольник, а не обычный.

fernandos ★★★
()
Ответ на: комментарий от no-such-file

Во многих и подбирают.

Но почему не должно-то быть? Вырожденные/бесполезные/однобокие примеры повсюду в обучении, например сначала детей учат округлять (на математике) и значительно позже округлять правильно (на физике).

Сомневаюсь, что книжка типа «ооп для чайников» предполагает превратить человека в программиста.

ya-betmen ★★★★★
()
Ответ на: комментарий от crutch_master

В какой-нибудь жабке просто нет технической возможности не рассматривать их как догму.

Это не совсем так. Проблемы у Java не в том, что там частный случай ООП вбит намертво в рантайм, а в том, что в Java очень тяжело делать data-oriented design. Поэтому мой любимый трюк с «DoD внизу, ООП вверху» там не прокатывает.

А так над JVM можно делать кастомные объектные модели, а сейчас еще и с GraalVM это можно делать достаточно эффективно.

Отказаться - значит признать, что философия топ ынтерпрайз язычка оказалась ошибочной.

Давай условимся, что мы если и рассматриваем проблемы дизайна конкретных ЯП, то не смешиваем их с ООП вообще. Это, всё же, совсем разные темы.

aist1 ★★★
()

А не надо никаких искусственных идей, появляются общие функции- удалить, нарисовать, стереть - вводишь базовый класс, нет - идите в ..оопу и там полиморфируйте скоко хотите.

ilovewindows ★★★★★
()
Последнее исправление: ilovewindows (всего исправлений: 1)
Ответ на: комментарий от no-such-file

интерфейс другой

Можно нагородить класс калькулятора. Но это много лишнего кода и тебе все равно в основных классах нужно будет выделить общие поля для расчета: b и h, как в ромбе так и в треугольнике. Поэтому лучше так:

interface Triangable
int b()
int h()

default int square() {bh/2;}

В ромбе переопределяешь метод: square() { super.square() * 2 }

foror ★★★★★
()

Ну это же шизуха полная. Детский сад, штаны на лямках.

квадрат, прямоугольник, ромб, трапеция

Частные случаи четырехугольника. Поэтому делаем класс Четырехугольник, внутри - метод для расчета площади произвольного четырехугольника и пересечения двух произвольных четырехугольников.

Все. Квадратом или ромбом объект будет становиться в зависимости от данных в рантайме. Причем тут классы?

James_Holden ★★★★
()
Ответ на: комментарий от foror

переопределяешь метод

Лишняя цепочка вызовов, лишние вычисления. Гораздо проще использовать один и тот же SquareCalc, просто давать h/2 в качестве второго параметра. Поскольку класс исключительно для вычисления площади, то нас не волнует как там это храниться. Для хранения у нас есть Shape.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Когда у тебя будет список из Shape, тебе придется писать дополнительный код для выбора нужного калькулятора. Я как понимаю там могут быть не только четырехугольники. Как минумум был речь о круге.

foror ★★★★★
()
Ответ на: комментарий от ya-betmen

А первом классе детей учат складывать 2 яблока и 3 апельсина.

Не яблоки с апельсинами складывать же, а их количества. Ожидается, что дети уже слегка владеют абстракцией и понемают разницу между объектом и его свойствами.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от aist1

наследование

для реализации механизмов композиции

Ничоси.

Nervous ★★★★★
()
Ответ на: комментарий от ilovewindows

А не надо никаких искусственных идей, появляются общие функции- удалить, нарисовать, стереть - вводишь базовый класс, нет - идите в ..оопу и там полиморфируйте скоко хотите.

Во. +100500 (если не придираться к формулировке, не упоминающей требование полиморфного поведения). Плясать надо от конкретной задачи.

dimgel ★★★★★
()

Я правильно понимаю, что вы делаете вывод, что раз не все объекты однозначно укладываются в единую иерархию, то ООП не нужен?

alpha ★★★★★
()
Ответ на: комментарий от James_Holden

Поэтому делаем класс Четырехугольник, внутри - метод для расчета площади произвольного четырехугольника и пересечения двух произвольных четырехугольников.

Это при условии, что эти методы для произвольных четырёхугольников проще, чем если забабахать их в отдельные классы под каждый вид четырёхугольников.

Вообще, вопрос «является ли квадрат прямоугольником», как мне помнится, был засадой в контексте мутабельных объектов. В том примере, что я видел, инвариант ломали через мутабельность примерно так (псевдокод):

Rectangle r = Rectangle()
r.width = 10
r.height = 10
assert(r.square == 100)
r.width = 20
assert(r.square == 200)

Rectangle r = Square()
r.width = 10   // т.к. квадрат, то r.height тоже становится 10
r.height = 10   // NOOP
assert(r.square == 100)
r.width = 20   // т.к. квадрат, то r.height тоже становится 20
assert(r.square == 200)  // ОШИБКА

И конкретно этот косяк лечится элементарно – иммутабельностью. Хз, может и с иммутабельными можно что-то аналогичное сочинить; но повторюсь – @ilovewindows правильно написал: в каждом конкретном случае нужно исходить из задачи.

dimgel ★★★★★
()
Ответ на: комментарий от alpha

Я правильно понимаю, что вы делаете вывод, что раз не все объекты однозначно укладываются в единую иерархию, то ООП не нужен?

Бггг. Что значит не все укладываются?! Вон в жаве прекрасно укладывается: всё на свете наследуется из java.lang.Object. =)

dimgel ★★★★★
()
Ответ на: комментарий от dimgel

Это при условии, что эти методы для произвольных четырёхугольников проще, чем если забабахать их в отдельные классы под каждый вид четырёхугольников.

Тут такое дело - в будущем все равно задача изменится так, что появятся произвольные четырехугольники. ТС же явно на это намекает. Так что проще в данной ситуации именно сразу решить для произвольных и не мучиться.

Вообще, вопрос «является ли квадрат прямоугольником», как мне помнится, был засадой в контексте мутабельных объектов. В том примере, что я видел, инвариант ломали через мутабельность примерно так

Отличный пример, в том числе того о чем я пишу. Если бы был просто класс четырехугольника - проблема никогда бы не возникла.

Принцип KISS никто не отменял.

в каждом конкретном случае нужно исходить из задачи

+100500

Поэтому я и пишу что эта тема - шизуха. Так задача не ставится.

James_Holden ★★★★
()

а зачем эти иерархии выводить? в трехмерной графике все из треугольников состоит (трисов), двумерной - совокупность линий, т.е. векторов, с помощью этих векторов и определяется collision detection

tz4678 ★★
()
Последнее исправление: tz4678 (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Здесь нет иерархии, это ошибка новичка от ООП.

Так-то в куче букварей по ооп именно пример с классами фигур. Ты считаешь, что авторы этих букварей - идиоты и ничерта не понимают в том, о чем пишут?

Я считаю, что ты их не читал. Если бы читал, то знал бы, что там этот пример приведён как раз как для разбора, когда есть наследование интерфейса, а когда нет.

t184256 ★★★★★
()
Ответ на: комментарий от t184256

Примитивные типы там имеют обертки. Оно, на вкус «так себе», но результат тот же.

aist1 ★★★
()

С телефона сложно лолировать, но я попробую.

Нам понадобятся несколько классов: 1Д, 2Д объекты и пространство с координатами.

2Д объект хранит в себе граф 1Д объектов с их угловым разрешением и длиною (ну то есть мы хардкодим 1Д объекты как рёбра отрезки)

Этого достаточно для того, чтобы нарисовать все евклидовые фигуры на пространстве.

Сами фигуры наследуется от стандартного 2Д объекта и проксируют свои специфичные методы.

Квадрат наследуется от прямоугольника. Ромб наследуется от треугольника.

Ну и соотвественно прямоугольник принимает два размера, квадрат переопределяет этот метод и второй размер игнорирует.

Ромб вообще имеет те же методы, что и треугольник, просто добавляя под капотом ещё один такой же.

Сами фигуры понятие не имеют как почитать их площадь или пересечение с другими фигурами потому, что во первых площадь будет зависеть от поверхности, а про другие фигуры они вообще ничего не знают.

И только разложив их в пространстве с определёнными координатами мы сможем посчитать площадь или пересечение прямых отрезков.

system-root ★★★★★
()
Последнее исправление: system-root (всего исправлений: 1)

Окей. Я тут выкроил часик, изолью свой сок мозга по данной теме.

Nervous, это и для тебя тоже с пояснением, что я имел в виду про композицию.

crutch_master, мой ответ будет не совсем на твой вопрос в той форме как ты его тут поставил, но ты поймешь)

Я всего лишь расскажу, как с математической точки зрения правильно делать иерархии (не только) классов. Я не буду рассматривать вопросы эффективной реализации таких иерархий в фон-неймановских или альтернативных вычислительных архитектурах.

Всё дело в композициональности (composability) в изначальном смысле этого слова. Дело в том, что есть вещи, поддающиеся композиции типа «собрать домик из кирпичиков» (сложную программу из операционной семантики примитивных операций), есть вещи, композиции не поддающиеся (например, значение фразы «синее море» из значений слов «синий» и «море» по отдельности), и есть вещи, которые трудно поддаются композиции. Например — эти самые геометрические фигуры, взятые в контексте иерархий.

Трудность здесь состоит в том, что фигуры не удается эффективно разбить на более простые примитивы, получив при этом ограниченный словарь этих примитивов, из которых потом можно было бы конструировать новые сущности, как клетки — из белков. Не удается не по причине каких-то фундаментальных проблем, а по причине того, что наш брат находится в «пузыре» типов данных конкретных ЯП. Вот именно это и есть та самая догма, о которой я говорил выше.

Теперь про «иерархии». А точнее, про деревья. Так как кто-то когда-то сказал, что множественное наследование — зло. На самом деле не зло, а просто потому что «синее» и «море» не даст нам «синего моря» автоматически.

Деревья и иерархии одиночного наследования прижились потому, что в рамках дерева все утверждения, справедливые для некоторого узла, справедливы и для всех его потомков. Так реализуется принцип LSP и так на много проще делать вывод типов. А LSP — это полностью про композициональность. Обобщение принципа композициональности — это про теория колмогоровской сложности (алгоритмической информации). Всем рекомендую, там много следствий из базовых теорем, которые закроют много спорных вопросов в практическом программировании.

Итак, я остановлюсь на деревьях. Геометрические фигуры — не сферические кони в вакууме. Иерархией для них будет многомасштабное вейвлет-разложение и соответствующие кодировки, направленные на компактификацию описаний в пространстве вейвлет-коэффициентов через обычную композициональность. Эти кодировки — и будут классы. Обратное вейвлет-преобразование будет нам давать «объекты» — изображения геометрических фигур (поведения объектов).

Совершенно отдельная история — как с такими классами-объектами можно работать в железе. Кто-то считает, что тут хороши матричные процессоры, и нейросети себя неплохо так показывают в индуктивном выводе подобного рода «иерархических репрезентаций». Я тут погружаться глубоко не буду. Скажу просто, что нам никто не запрещает выходить за рамки привычных нам примитивных типов и коллекций над ними. Какие хотим кодировки, такие и изобретаем. Надо — реализуем прямую аппаратную поддержку всего, что слишком медленно ворочается.

Короче, пример с геометрическими фигурами на самом деле очень простой. Куда сложнее вывести эффективные иерархии для «высокоуровневых многомодальных смыслов», почему задача поиска эффективной композиции для вещей типа «синее» + «море» и считается запредельной.

А то, что «современные» ООЯП — немощный отстой, так это давно уже поняли. Нужно идти гораздо глубже в кодировки, в теорию информации и в ту же эпистемологию (вопросы представления знаний), чтобы иметь возможность добраться до того самого «базиса», на котором начинает эффективно работать композициональность. В твоей задачке для геометрических фигур такого базиса с ходу не видно и, без перехода к другим репрезентациям, его не предложить.

aist1 ★★★
()
class Точка{
   int X;
   int Y;
}

class Путь {
   ...
   Путь(Точка... точки){
      ...
   }

   boolean путьЗамкнут(){
      ...
   }
   
   boolean естьСамопересечения(){
      ...
   }

   boolean этоФигура(){
      ...
   }
   
   boolean этоМногогранник(){
      ...
   }
   
   boolean этоКвадрат(){
      ...
   }


   ...
}

class Многогранник extends Путь throws МногогранникОшибка{
   Многогранник(Точка ... точки) { 
      super(точки);
      if(!этоМногогранник()) {
         throw new МногогранникОшибка("не многогранник!");
      }
   }

   Number площадь(){
      ...
   }

   Многогранник пересечение(Многогранник фигура){
      ...
   }
}

class Квадрат extends Многогранник throws КвадратОшибка{
   Квадрат(Точка ... точки) { 
      super(точки);
      if(!этоКвадрат()) {
         throw new КвадратОшибка("не квадрат!");
      }
   }

   Квадрат(Точка леваяВерхняя) {      
      super(точки(леваяВерхняя));   
   }

   private Точка[] точки(Точка леваяВерхняя) {
      ...
   }

}
olelookoe ★★★
()

Вот тебе пример ООП. Пересечение двух четырёхугольников это перебор, там от треугольника до шестиугольника может получиться. Тяжеловато все эти кейсы правильно рассчитать.

#include <cmath>
#include <memory>
#include <ostream>
#include <iostream>

struct xy { double x, y; };
std::ostream& operator<<(std::ostream& out, const xy& p) {
    return out << '(' << p.x << ',' << p.y << ')';
}

class Polygon {
public:
    virtual ~Polygon() noexcept {}
    virtual size_t n() const = 0; // number of vertices
    virtual const char* name(size_t) const = 0; // vertex name by index
    virtual xy p(size_t) const = 0; // vertex xy bt index
    virtual double s() const = 0; // polygon square
};
std::ostream& operator<<(std::ostream& out, const Polygon& p) {
    const auto n = p.n();
    for (size_t i = 0; i != n; ++i)
        out << p.name(i) << p.p(i);
    return out;
}
std::ostream& operator<<(std::ostream& out, const std::unique_ptr<Polygon>& p) {
    return out << *p;
}

class Quadrangle: public Polygon {
public:
    ~Quadrangle() noexcept override {}
    size_t n() const final { return 4; }
    const char* name(size_t i) const final {
        switch (i) {
            case 0: return "A";
            case 1: return "B";
            case 2: return "C";
            case 3: return "D";
        }
        throw std::range_error("quadrangle vertex index out of range");
    }
    xy p(size_t i) const final {
        switch (i) {
            case 0: return a();
            case 1: return b();
            case 2: return c();
            case 3: return d();
        }
        throw std::range_error("quadrangle vertex index out of range");
    }
    virtual xy a() const = 0;
    virtual xy b() const = 0;
    virtual xy c() const = 0;
    virtual xy d() const = 0;
};

class Rectangular: public Quadrangle
{
public:
    ~Rectangular() noexcept override {}
    xy a() const final { return xy{-width()/2, -height()/2}; } // bottom left
    xy b() const final { return xy{ width()/2, -height()/2}; } // bottom right
    xy c() const final { return xy{ width()/2,  height()/2}; } // top right
    xy d() const final { return xy{-width()/2,  height()/2}; } // top left
    virtual double width() const = 0;
    virtual double height() const = 0;
};

class Square: public Rectangular
{
public:
    ~Square() noexcept final {}
    Square() = delete;
    explicit Square(double side): m_side(side) {}
    static std::unique_ptr<Polygon> create(double side) { return std::make_unique<Square>(side); }
    double s() const final { return m_side*m_side; };
    double width() const final { return m_side; }
    double height() const final { return m_side; }
private:
    double m_side;
};

class Rectangle: public Rectangular
{
private:
    Rectangle() = delete;
public:
    ~Rectangle() noexcept final {}
    Rectangle(double width, double height): m_width(width), m_height(height) {}
    static std::unique_ptr<Polygon> create(double w, double h) { return std::make_unique<Rectangle>(w, h); }
    double s() const final { return m_width*m_height; }
    double width() const final { return m_width; }
    double height() const final { return m_height; }
private:
    double m_width, m_height;
};

class Rhombus: public Quadrangle
{
public:
    ~Rhombus() noexcept final {}
    Rhombus() = delete;
    Rhombus(double dx, double dy): m_dx(dx), m_dy(dy) {}
    static std::unique_ptr<Polygon> create(double dx, double dy) { return std::make_unique<Rhombus>(dx, dy); }
    double s() const final { return m_dx*m_dy/2; }
    xy a() const final { return xy{-m_dx/2, 0      }; } // left
    xy b() const final { return xy{      0, -m_dy/2}; } // bottom
    xy c() const final { return xy{ m_dx/2, 0      }; } // right
    xy d() const final { return xy{      0,  m_dy/2}; } // top
private:
    double m_dx, m_dy;
};

class Trapezoid: public Quadrangle
{
public:
    ~Trapezoid() noexcept final {}
    Trapezoid() = delete;
    Trapezoid(double bottom, double top, double height, double disp)
        : m_bottom(bottom), m_top(top), m_height(height), m_disp(disp) {}
    static std::unique_ptr<Polygon> create(double bottom, double top, double height, double disp) {
        return std::make_unique<Trapezoid>(bottom, top, height, disp);
    }
    double s() const final { return (m_bottom + m_top) * m_height / 2; }
    double mx() const { return m_disp + (m_top - m_bottom)/2; }
    xy a() const final { return xy{ -(m_bottom + mx())/2, -m_height/2}; } // left bottom
    xy b() const final { return xy{  (m_bottom - mx())/2, -m_height/2}; } // right bottom
    xy c() const final { return xy{  (m_top    + mx())/2,  m_height/2}; } // right top
    xy d() const final { return xy{ -(m_top    - mx())/2,  m_height/2}; } // left top
private:
    double m_bottom, m_top, m_height, m_disp;
};

class Transform: public Polygon {
public:
    ~Transform() noexcept override {}
    Transform() = delete;
    explicit Transform(std::unique_ptr<Polygon>&& original): m_original(std::move(original)) {}
    double s() const final { return m_original->s(); }
    size_t n() const final { return m_original->n(); }
    const char* name(size_t i) const final { return m_original->name(i); }
    Polygon* original() const { return m_original.get(); }
private:
    std::unique_ptr<Polygon> m_original;
};

class Move: public Transform {
public:
    ~Move() noexcept override {}
    Move() = delete;
    Move(double dx, double dy, std::unique_ptr<Polygon>&& original):
        Transform(std::move(original)), m_dx(dx), m_dy(dy) {}
    static std::unique_ptr<Polygon> create(double dx, double dy, std::unique_ptr<Polygon>&& original) {
        return std::make_unique<Move>(dx, dy, std::move(original));
    }
    xy p(size_t i) const final {
        const auto p = original()->p(i);
        return xy{m_dx + p.x, m_dy + p.y};
    }
private:
    double m_dx, m_dy;
};

class Rotate: public Transform {
public:
    ~Rotate() noexcept final {}
    Rotate() = delete;
    Rotate(double alpha, std::unique_ptr<Polygon>&& original):
        Transform(std::move(original)), m_alpha(alpha) {}
    static std::unique_ptr<Polygon> create(double alpha, std::unique_ptr<Polygon>&& original) {
        return std::make_unique<Rotate>(alpha, std::move(original));
    }
    xy p(size_t i) const final {
        const auto p = original()->p(i);
        const auto co = std::cos(m_alpha);
        const auto si = std::sin(m_alpha);
        return xy{p.x*co - p.y*si, p.x*si + p.y*co};
    }
private:
    double m_alpha;
};

int main()
{
    std::cout << Square::create(2) << std::endl;
    std::cout << Rectangle::create(4, 2) << std::endl;
    std::cout << Rhombus::create(2, 4) << std::endl;
    std::cout << Trapezoid::create(4, 2, 2, 1) << std::endl;
    std::cout << Move::create(1, 1, Square::create(2)) << std::endl;
    std::cout << Rotate::create(M_PI/4, Rhombus::create(2*std::sqrt(2), 2*std::sqrt(2))) << std::endl;
    return 0;
}

Вывод програмы:

[iliyap@saturn oop]$ ./oop 
A(-1,-1)B(1,-1)C(1,1)D(-1,1)
A(-2,-1)B(2,-1)C(2,1)D(-2,1)
A(-1,0)B(0,-2)C(1,0)D(0,2)
A(-2,-1)B(2,-1)C(1,1)D(-1,1)
A(0,0)B(2,0)C(2,2)D(0,2)
A(-1,-1)B(1,-1)C(1,1)D(-1,1)
[iliyap@saturn oop]$ 
iliyap ★★★★★
()
Ответ на: комментарий от ya-betmen

2 яблока и 3 апельсина равняются фруктовому салату либо заправке для глинтвейна. Смотря кто спрашивает, математичка или физрук.

P.S. Следует ли наследовать салат от глинтвейна или глинт от салата? С одной стороны салат есть частный случай глинтвейна с нулевым количеством вина. С другой — глинтвейн есть салат с винным соусом. Поведение у них более-менее совпадает.

ugoday ★★★★★
()
Ответ на: комментарий от aist1

Выдалась еще минутка. Дополню. Теперь с более технической стороны.

Всё дело в т.н. репрезентациях. Нам, прогерам, сейчас на много проще, чем раньше. Умный дядька Колмогоров доказал теорему о том, что Машина Тьюринга является универсальной репрезентацией. Т.е. если что-то не описываемо на языке программирования, то можно ставить даже вопрос о его физическом существовании.

Короче, мы могли бы держать хвост пистолетом в разговорах за пивом с продвинутыми гуманитариями о сущности всего происходящего. Но есть нюансы. Как и йогурты, не все репрезентации нам, людям, одинаково полезны. В смысле, не со всеми мы можем эффективно работать. Я поясню.

В чем каверзность задачки с геометрическими фигурами? В том, что эта задачи из «домена изображений» (образные репрезентации), но для неё нужно предложить чисто «символьную» модель. Людям старой школы ИИ будет понятно, что тут нас ждет фейл хотя бы даже просто на концептуальном уровне.

Я уже привел пример с вейвлет-декомпозицией изображений, как механизма их «концептуализации через сжатие». И ML сейчас неплохо справляется с некоторыми частными случаями таких зада. Проблема для нас, программистов в том, что ML-то справляется, а мы - нет. Мы не можем «вручную» создавать репрезентации для подавляющего большинства феноменов реального мира.

Что это всё значит? ТС, например, говорит, что Java - гавно. Или подразумевает, но не говорит. Г-н Торвальдс говорит, что нет ничего, лучше С, так как на нем можно накидать любую объектную модель (но почему-то нельзя накидать деструкторы). Кто-то странный говорит, что нас ждет Software 2.0. Я бы так не хайповал, у них там в ML проблем вагон и маленькая тележка. Но — суть: есть ли такой язык программирования, на котором решение «суперсимвольных» задач было бы доступно человеку? Все существующие ООЯП для этого плохи. Шаг влево-вправо и ты выпал из их весьма узкой зоны эффективности.

Как частный случай проблемы, в наших ЯП весьма примитивная система типов. Мы очень много внимания уделяем некоторым частным классам алгоритмов, а со структурами данных полная ООПа, как любит тут говорить ТС. Нет, мапы, массивы, деревья и графы — это далеко не все структуры данных. И даже не начало списка. И если это всё сразу кажется сложно и не нужно — то вот он, тот самый пузырь, в котором мы сидим. Нам кажется это ненужным, мы это и не изучаем. А раз мы это не изучаем, то всё, что мы не понимаем, нам кажется ненужным. А потом думаем, как натянуть символьную модель (ООЯП) на образный домен (геометрические фигуры).

aist1 ★★★
()
Ответ на: комментарий от Nervous

Божественно %)

Выражайся конкретнее, тебе название не понравилось или подход? Твоей реализации мы конечно же не увидим.

foror ★★★★★
()
Ответ на: комментарий от foror

Как минумум был речь о круге.

Во-первых о круге речи не было. Во-вторых круги и эллипсы делаются из квадриков, или кубиков – смотря что ещё там надо.

придется писать дополнительный код для выбора нужного калькулятора

Как бы логично, что каждая фигура в общем случае имеет свою формулу для расчёта площади. Классы упрощённых расчётов не обязаны соответствовать типу фигуры. В частности класс который вычисляет площадь как a*b подходит для любых фигур с двумя параметрами. Нужно просто правильно инициализировать эти параметры калькулятора из параметров фигуры. Инициализатор (билдер) это отдельная сущность.

Я уже начал уставать повторять, что структура программы (классы и наследование) не отражает структуру предметной области. Структура предметной области задаётся в динамике взаимодействия объектов.

no-such-file ★★★★★
()
Ответ на: комментарий от aist1

Про композициональность и вейвлеты ничего не понял, но очень интересно.

«современные» ООЯП — немощный отстой, так это давно уже поняли.

Трудно не согласиться. Мне кажется, что наследование нужно в основном для реализации полиморфного поведения, и когда разное поведение над одними и теми же объектами начинает требовать разных иерархий, современный ООП окончательно сдувается.

Классификация объектов зависит от текущей задачи, ее нельзя вырубить в камне раз и навсегда.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 3)
Ответ на: комментарий от tz4678

а зачем эти иерархии выводить?

Ты хотел спросить зачем нужно наследование в ООП?

совокупность линий, т.е. векторов, с помощью этих векторов и определяется collision detection

Да, я тоже всё могу сделать через полигон. Тут дело в подходе, а не геометрии. Для любой другой задачи тебе скажут, что надо делать классы и наследование и ты будешь наследовать треугольники от квадратов.

crutch_master ★★★★★
() автор топика
Ответ на: комментарий от aist1

Я бы так не хайповал, у них там в ML проблем вагон и маленькая тележка

есть ли такой язык программирования, на котором решение «суперсимвольных» задач было бы доступно человеку

А нужен ли такой язык? В ML проблем конечно есть, но без ML мы с любым языком будем в жопе. Потому что человечество накапливало знания в распределённом хранилище книг и обрабатывало на распределённом кластере мозгов. Соотношение количества информации и черепных процессоров исторически всегда сохранялось: большее количество знаний распределялось по большему количеству голов (специализация). С появлением компов генерирование информации возросло многократно, а вот с обработкой проблема – не хватает людей. Не хватает уже даже людей которые могут запрограммировать комп. Единственный способ решения этой проблемы, это сделать так, чтобы машина которая генерирует информацию, сама же её и обрабатывала без участия человека. Тогда мы таки сможем выйти на «сверхчеловеческий» прогресс. Всё остальное будет топтанием на месте, никакие «суперязыки» не помогут нам преодолеть наши ограниченные возможности как вида.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от crutch_master

данной задачи не нужна иерархия.

Наверняка ведь есть задачи, где нужна.

ООП - overrated

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

Nervous ★★★★★
()
Ответ на: комментарий от crutch_master

скажут, что надо

Это - символ веры культа карго. Зачем так жить?

Надо понимать, зачем какой инструмент и методика нужны, а не заниматься культом карго.

James_Holden ★★★★
()
Ответ на: комментарий от aist1

А то, что «современные» ООЯП — немощный отстой, так это давно уже поняли.

В смысле отстой? Сейчас жавистов позовём.

Эти кодировки — и будут классы.

Ты понял, что тема - развод, но походу не понял в чём развод. Тут в самом деле не нужны классы квадраторомбов, правильный ответ прост и состоит из одной расхожей тут фразы.

crutch_master ★★★★★
() автор топика
Ответ на: комментарий от no-such-file

Всё остальное будет топтанием на месте, никакие «суперязыки» не помогут нам преодолеть наши ограниченные возможности как вида.

Вот это ты завернул! Я хотел просто ооп срачик, но чтобы он так далеко зашел..

crutch_master ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.