LINUX.ORG.RU

Старт пятничного треда

 , , ,


1

6

Привет, ЛОР!

Сегодня видел статью на Хабре про D и кросс-платформенный GUI для него. Аналогичную статью не так давно видел для Go. Думаю скоро и для Rust что-то будет «взлетать» из нужных батареек (да, для меня GUI нужен, а Qt я не люблю). Возник вопрос - что-то из них взлетит или нет, какой язык какую нишу сейчас занимает, какую нишу какой язык может занять.

Еще вопрос к любителям D - в чем его профиты? Я так и не увидел, чем он лучше Go, Rust.

★★

Последнее исправление: silver-bullet-bfg (всего исправлений: 1)

Ответ на: комментарий от menangen

Наследованием.

// test project main.go
package main

import "fmt"

type T1 struct {
	str string
}

func (t *T1) test() {
	fmt.Printf("Menangen %s.\n", t.str)
}

type T2 struct {
	T1
	str2 string
}

func (t *T2) test2() {
	t.test()
	fmt.Printf("Menangen %s.\n", t.str2)
}

func main() {
	mess := T2{T1{"школьник"}, "яблофаг"}
	mess.test2()
}

Чем не наследование? Пишется по-другому? До множественного варианта, я надеюсь сам додумаешься?

Полиморфизмом

// test project main.go
package main

import "fmt"

type T1 struct {
	str string
}

func (t *T1) test() {
	fmt.Printf("%s яблофаг.\n", t.str)
}

type T2 struct {
	str string
}

func (t *T2) test() {
	fmt.Printf("%s школьник.\n", t.str)
}

type T interface {
	test()
}

func echo(str T) {
	str.test()
}

func main() {
	var t [2]T
	t[0] = &T1{"Menangen"}
	t[1] = &T2{"Menangen"}
	for _, i := range t {
		echo(i)
	}
}

Чем не полиморфизм?

но это не аналог методов в классах

Чем? Apple не одобрил?

геттеры-сеттеры укакаешься писать для таких структур

Не стоит испражняться за компьютером. Я понимаю, что ты уже привык это делать на ЛОРе, но всё же, поменяй привычку пока не поздно.

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

Хочешь посоревноваться

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

Обещанный? Кем и кому?

Можешь не оправдываться.

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

Си идеален, кроме того, что устарел лет на 20.

Любопытно каким ты видишь правильное развитие С.

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

ты же мне покажешь реальный юзкейс шаблонов?

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

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

На mess можно вызвать test? Не test2, а именно test?

Самому стало интересно, залил тест в песочницу на https://golang.org/#, исправил чуток на

func main() {
	mess := T2{T1{"школьник"}, "яблофаг"}
	mess.test2()
	mess.test()
}

вывод:

Menangen школьник.
Menangen яблофаг.
Menangen школьник.
yyk ★★★★★
()
Ответ на: комментарий от Ivan_qrt

Так наследование, это когда ты инициализируешь T с содержимым «Menangen», а уже T1 и T2 после инициализации имеют внутри себя и «Menangen», и str(), которое возвращает «Menangen2» T2, и «Menangen1» T1, к примеру. А так ты скопипастил строки и всё - это ж элементарщина. Также разговор был про сеттеры. Нужно, чтобы при установке значения в структуре T.name записывалась не просто переменная строковая, а изменённая, например:
T.name = «menangen»
При считывании T.name было бы равно "(menangen)". И так у всех структур: T, T1, T2. Конечно, желательно без копипаста. Чтобы метод был написан один раз для T.

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

Чем не наследование?

Тем, что это встраивание. Есть разница:

package main

import "fmt"

type T1 struct {
	str string
}

type T2 struct {
	T1
	str2 string
}

func main() {
	obj := new(T1)
	obj  = new(T2)
	fmt.Println("done")
}

# command-line-arguments
/tmp/sandbox128261485/main.go:16: cannot use new(T2) (type *T2) as type *T1 in assignment

Наследование же образует подтип (хотя Ocaml не совсем удачный пример, там типы отделены от классов, в остальных статическитипизированных языках с ООП будет то же самое):

class t1 = object
	val str = ""
end
 
class t2 = object
	inherit t1
	val str2 = ""
end
 
let () =
	let obj = ref (new t1) in
	obj := new t2 ;
	print_endline "done"

done

Но большинство юзкейсов наследования оно покрывает, да.

korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 2)
Ответ на: комментарий от menangen

Так наследование, это когда ты инициализируешь T с содержимым «Menangen», а уже T1 и T2 после инициализации имеют внутри себя и «Menangen», и str(), которое возвращает «Menangen2» T2, и «Menangen1» T1, к примеру.

Конструкторы не наследуются, в практически любом ООП-языке тебе придётся писать инициализацию явно. Ничто не мешает точно также написать функцию-конструктор в Go, что обычно все и делают.

Также разговор был про сеттеры.

Это которых нет в SmallTalk'е и C++ например?

Нужно, чтобы при установке значения в структуре T.name записывалась не просто переменная строковая, а изменённая, например: T.name = «menangen» При считывании T.name было бы равно "(menangen)". И так у всех структур: T, T1, T2. Конечно, желательно без копипаста. Чтобы метод был написан один раз для T.

Лови:

package main

import "fmt"

type T1 struct {
	name string
}

func (t *T1) Name() string {
	return t.name
}

func (t *T1) SetName(n string) {
	t.name = fmt.Sprintf("(%s)", n)
}

type T2 struct {
	T1
}

type T3 struct {
	T1
}

// override name setter
func (t *T3) SetName(n string) {
	// using super.method
	t.T1.SetName("[" + n + "]")
}

func main() {
	type nameable interface {
		Name() string
		SetName(string)
	}
	ts := []nameable{&T1{}, &T2{}, &T3{}}
	for i, t := range ts {
		t.SetName(fmt.Sprintf("foo#%d", i))
	}
	for _, t := range ts {
		fmt.Println(t.Name())
	}
}

(foo#0)
(foo#1)
([foo#2])
korvin_ ★★★★★
()
Ответ на: комментарий от Ivan_qrt

До множественного варианта, я надеюсь сам додумаешься?

[vanga]Кстати, предугадывая его вопрос про ромб, скажу, что в этом случае Go выдаёт ошибку компиляции. Как для полей, так и для методов.

Решается вручную очевидным способом. [/vanga]

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

Тем, что это встраивание.

Ну да, оно другое, со своими нюансами, конечно. Но объекто-ориентированности это не отменяет.

Но большинство юзкейсов наследования оно покрывает, да.

А то, что не покрывает встраивание, докрывают интерфейсы. По сути, присваивать указателю на базовый класс объект дочернего ничем не отличается от присваивания объекта интерфейсу. Различия будут только в низкоуровневом кастовании из типа в тип. Но go не для этого.

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

А то, что не покрывает встраивание, докрывают интерфейсы.

А как же позднее связывание this (self)?

class parent = object (self)
	method foo = "parent foo"
	method bar = print_endline ("parent bar, " ^ self#foo)
end
 
class child = object
	inherit parent
	method foo = "child foo"
end
 
let () =
	let a = new parent
	and b = new child in
	a#bar ;
	b#bar

parent bar, parent foo
parent bar, child foo

package main

import "fmt"

type Parent struct {}

func (p *Parent) Foo() string {
	return "parent foo"
}

func (p *Parent) Bar() {
	fmt.Println("parent bar, " + p.Foo())
}

type Child struct {
	Parent
}

func (c *Child) Foo() string {
	return "child foo"
}

func main() {
	a := new(Parent)
	b := new(Child)
	a.Bar()
	b.Bar()
}

parent bar, parent foo
parent bar, parent foo
korvin_ ★★★★★
()
Последнее исправление: korvin_ (всего исправлений: 1)
Ответ на: комментарий от korvin_

Да, такая проблема есть. Позднее связывание, и vtable, как таковая, отсутствуют. При очень большом желании это можно решить при помощи рефлексии и свитча по типам. Но мне такое писать не хочется. Конкретно твой пример можно обойти, например, так:

package main

import "fmt"

type T interface {
	Foo() string
}

type Parent struct{}

func (p *Parent) Foo() string {
	return "parent foo"
}

func Bar(p T) {
	fmt.Println("parent bar, " + p.Foo())
}

type Child struct {
	Parent
}

func (c *Child) Foo() string {
	return "child foo"
}

func main() {
	a := new(Parent)
	b := new(Child)
	Bar(a)
	Bar(b)
}

Но, конечно, в более сложных ситуациях это приведёт к большим трудностям.

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

Хотя нет, про vtable я, похоже, не прав. Вот ещё один вариант:

package main

import "fmt"

type T interface {
	Foo() string
}

type Parent struct {
	this T
}

func (p *Parent) Init() {
	p.this = p
}

func (p *Parent) Foo() string {
	return "parent foo"
}

func (p *Parent) Bar() {
	fmt.Println("parent bar, " + p.this.Foo())
}

type Child struct {
	Parent
}

func (c *Child) Init() {
	c.this = c
}

func (c *Child) Foo() string {
	return "child foo"
}

func main() {
	a := new(Parent)
	a.Init()
	b := new(Child)
	b.Init()
	a.Bar()
	b.Bar()
}
parent bar, parent foo
parent bar, child foo

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

Ну пока мы докопались только до отсутствия познего связывания. Возможно я что-то упускаю, но для всего остального по части наследования, альтернатива есть. Да и для познего связывания, хоть и не очень нормальная, но альтернатива.

Если это обязательный критерий ОО языка, то тогда отменяет. Я в этом не уверен.

Как минимум, в go пользоваться объектами и писать ОО-код вполне удобно. Вот.

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

Я в этом не уверен.

А Бенджамин Пирс уверен, например.

Как минимум, в go пользоваться объектами и писать ОО-код вполне удобно. Вот.

Только благодаря утиной параше на интерфейсах (не как что-то плохое).

Deleted
()
Ответ на: комментарий от DarkEld3r

Не взлетит такой тролинг. Тут не в языке дело.

увы :((( ну хоть на 1C ЦарьЦарь что-нибудь напишет? или опять выдаст 'анскильно, ибо недоязычок' ? :))

anonymous
()
Ответ на: комментарий от Legioner

Я проникаюсь растом потихоньку, вообще довольно годная штука.

кстати, это же ты вроде писал Scheme4D — CTFE компиляциями, наподобие InterLib ?

вот вопрос: на расте подобное было бы написать проще/легче/сложнее и в чём, чем на D???

вроде бы по фичам раст для подобных извращений подходит: box, макросы вместо CTFE и т.п.

anonymous
()
Ответ на: комментарий от DarkEld3r

Нет кода на С++, который нельзя было бы переписать на Си без потери качества.
б) увеличивает количество кода в N-раз;

Забавно.

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

вот такой вот тест для этих трёх языков + С + С++: пишем хелловорд, собираем статически.

видим минимальный размер бинарника:

 C -- 5-10-20k в зависимости от выравнивания; 
 C++ --- 600k+ ибо libstd++ уже там. 
 далее, раст -- более вменяемо, можно отстрелить GC ибо borrowing/lending;
 далее, D -- 200k ибо Object в стандартной библиотеке должен уметь в рефлексию и typeinfo.
 и, хит сезона в номинации "толсто-толсто" -- Go 1.4.2 у которого хелловорд собирается в 2Mb 

я смеюсь с этих лалок, которые говорят что «на С строчек больше», а в итоговое 20k vs. 600k с крестами и накладные расходы на крестоту — не смотрят.

что показывает тест: минимализм стандартной библиотеки и фичу «не платишь, если не используешь». тут-то и выясняется, что С++ на самом деле сосёт, ибо простецкий std::cout цепляет за собой iostream, fstream и секцию инициализации для конструкторов и секцию для деструкторов в бинарнике (хотя можно и в С++ писать всего лишь puts()).

конечно, реально полезные хелловорды у разных языков будут разные.

anonymous
()
Ответ на: комментарий от DarkEld3r

Тут не в языке дело.

однако же, Максимка в презентации вполне разумно объяснила, почему именно D и почему именно CTFE и чем оно хорошо для JIT-а. думаю, и Legioner тоже про Scheme4D мог бы обяснить подобное.

впрочем, она вообще умница: компилятор «сишки» на окамле под LLVM, недолисп, рендерер и игродвижок — это то, что должен когда-нибудь написать себе каждый хакер, даже если он — девчонка.

anonymous
()
Ответ на: комментарий от Ivan_qrt

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

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

У тебя данные лет на 10 устарели, libstdc++ есть везде и отлично линкуется динамический, поэтому хэлловолды на С++ получаются по 17кб. И прежде чем ты начнешь мне кукарекать про необходимость тащить с собой libstdc++, вспомни, что твой 5-10-20кб на С без glibc или аналога тоже не взлетят.

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

вооот. значит, надо на сисколлы переписывать и от glibc отказываться совсем.

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

но тот же GoLang с хелловордом на 2Мб — вполне себе статический и самодостаточен. по идее, никакой glibc ему не нужен.

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

но тот же GoLang с хелловордом на 2Мб — вполне себе статический и самодостаточен. по идее, никакой glibc ему не нужен.

~$ cat ./test.cpp 
#include <iostream>

int main(){
    std::cout << "Hello World\n";
}
~$ clang++ -static -s ./test.cpp 
~$ du -h ./a.out 
1,4M    ./a.out
anonymous
()
Ответ на: комментарий от anonymous

кстати, это же ты вроде писал Scheme4D — CTFE компиляциями, наподобие InterLib ?

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

вот вопрос: на расте подобное было бы написать проще/легче/сложнее и в чём, чем на D???

В D всё просто. Получаем текст, выплёвываем текст. Это как старые лисповые макросы, произвольная функция, меняющая вход на выход. В расте макросы как в схеме - гигенические, паттерн-матчинг по сути, на своём микроязыке (тоже как в схеме). На них сложно написать такие извраты. Правда в расте есть т.н. compiler plugins, с ними вроде можно делать вообще что угодно. Думаю на них легко можно такое написать. Причём если в D «достучаться» до информации об объявленных переменных было невозможно, когда я это пробовал, то тут вроде доступно всё, наверное можно очень классную интеграцию сделать с хостовым языком.

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

glibc и libstc++ тоже отлично статический линкуются, получаются те же 1-2Мб хэлловорлды без динамических зависимостей вообще. Разница в том, что golang просто не умеет в динамическую линковку, поэтому хэлловорды по 2Мб это единственный вариант.

anonymous
()
Ответ на: комментарий от Legioner

Причём если в D «достучаться» до информации об объявленных переменных было невозможно, когда я это пробовал,

ну в 2.0 появилось typeinfo и трейты, где достучаться можно.

Правда в расте есть т.н. compiler plugins, с ними вроде можно делать вообще что угодно. Думаю на них легко можно такое написать.

да, имелось в виду что-то типа процедурных макросов, чтобы AST можно было в CTFE руками делать каким нужно.

вообще да, ещё у реализации на ржавчине и CG отстреливаемый получился бы, и через каналы и корутины в чём-то проще можно компилятор сделать (где-то была презентация Роба Пайка из GoLang про организацию парсера/лексера/компилятора на горутинах) — хотя чтобы CTFE ещё и распараллеливался по корутинам через каналы это наверное оверкилл, всё-таки.

такой минималистичный минимализм — в смысле рантайма.

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

вообще все эти языки лалки потому что минимальный статический хелловорд это около тех же самых 1-2 Мб. вся надежда на ржавчину.

Разница в том, что golang просто не умеет в динамическую линковку

это ещё полбеды. там GC неостреливаемый, а в расте например каналы и корутины — реализованы через стандартную библиотеку, то есть, с точки зрения модели памяти и рантайма — язык модульнее.

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

Они же вообще GC убрали, даже из stdlib пропал, только RC оставили. И рантайм урезали до минимума: https://github.com/rust-lang/rust/commit/0efafac398ff7f28c5f0fe756c15b9008b3e...

When using Rust in an embedded context, it should now be possible to call a Rust function directly as a C function with absolutely no setup, though in that case panics will cause the process to abort. In this regard, the C/Rust interface will look much like the C/C++ interface.

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

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

anonymous
()
Ответ на: комментарий от tailgunner

но почему? ведь если сделать map-файл при линковке, а потом взять хелловорд через сисколлы (или с linuxassembly)  — вот нафига это вот всё в конечном бинарнике, если оно не используется? ну ладно там atexit, парсинг args, env и всё что выполняется до main (в С++ там ещё будут конструкторы и после него — деструкторы). ну может реализация malloc ещё пригодится.

а вот остальные эти 510кб — это «дохлая ворона, не пригодилааась».

anonymous
()
Ответ на: комментарий от tailgunner

алсо, можно и вывод hello world не писать:

1. printf("hello world\n");
2. puts("hello world \n");
3. exits("hello world"); /** OH SHI.. у нас линакс, а не Plan9 */

а сразу написать int main(){return 0;}

вопрос, почему он толще ассемблерного или на сисколлах syscall(_exit) ?

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

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

C — 5-10-20k в зависимости от выравнивания;

530k, если линковать static.

но почему?

Да какая разница? Факт налицо.

а вот остальные эти 510кб — это «дохлая ворона, не пригодилааась».

Как и в Си++

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

Где вы всего этого говна набрались, ты же мне покажешь реальный юзкейс шаблонов?

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

cyanide_regime
()
Ответ на: комментарий от eao197

ACE_Acceptor сойдет в качестве реального юзкейса?

что ты пытаешься объяснить этой анскильной обезьяне? он слишком туп для того чтобы понять как готовить шаблоны.

cyanide_regime
()
Ответ на: комментарий от anonymous

я смеюсь с этих лалок, которые говорят что «на С строчек больше», а в итоговое 20k vs. 600k с крестами

Ты эти 600к не руками пишешь.

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

в крестах дополнительно не пригодились: конструкторы и деструкторы, RTTI, исключения

-fno-exceptions -fno-rtti -nostdlib и вперёд с прерываниями писать, уменьшатели мамкины

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

раст — более вменяемо, можно отстрелить GC

В расте нет ГЦ вообще (когда-то, вроде, был). Есть возможность его добавить, которая не реализована, вроде.

конечно, реально полезные хелловорды у разных языков будут разные.

Вот именно.

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

Мне интересно — насколько хорош может быть GC в расте? Там же вроде нет runtime reflection. Как GC узнает, где указатель, где число? Консервативный GC по-моему это плохой вариант, который мало кому нужен. Да и вообще rust не сочетается с GC никак.

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